filemanager.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. #include "filemanager.h"
  2. #include "scintillaeditview.h"
  3. #include "scintillahexeditview.h"
  4. #include "CmpareMode.h"
  5. #include "ccnotepad.h"
  6. #include <QMessageBox>
  7. #include <QFile>
  8. #include <QtGlobal>
  9. #include <qscilexer.h>
  10. FileManager::~FileManager()
  11. {
  12. }
  13. ScintillaEditView* FileManager::newEmptyDocument()
  14. {
  15. ScintillaEditView* pEdit = new ScintillaEditView(nullptr);
  16. return pEdit;
  17. }
  18. ScintillaHexEditView* FileManager::newEmptyHexDocument()
  19. {
  20. ScintillaHexEditView* pEdit = new ScintillaHexEditView(nullptr);
  21. return pEdit;
  22. }
  23. //从尾部找前面的换行符号。返回的是需要回溯的个数
  24. int findLineEndPos(const char* buf, int size)
  25. {
  26. int ret = 0;
  27. bool isfound = false;
  28. for (int i = size - 1; i >= 0; --i)
  29. {
  30. if (buf[i] == '\n')
  31. {
  32. isfound = true;
  33. break;
  34. }
  35. ++ret;
  36. }
  37. //如果没有找到,怀疑是mac格式,按照\r结尾解析
  38. if (!isfound)
  39. {
  40. for (int i = size - 1; i >= 0; --i)
  41. {
  42. if (buf[i] == '\r')
  43. {
  44. isfound = true;
  45. break;
  46. }
  47. ++ret;
  48. }
  49. }
  50. if (isfound)
  51. {
  52. return ret;
  53. }
  54. //说明是一个巨长的行,这种情况不是很好。直接读取了,不管是否进行了行截断
  55. return 0;
  56. }
  57. //从行首找后面的换行符号。返回的是需要前进的个数,即把前面掐掉一节,让返回在一行的行首位置
  58. int findLineStartPos(const char* buf, int size)
  59. {
  60. int ret = 0;
  61. bool isfound = false;
  62. for (int i = 0; i < size; ++i)
  63. {
  64. ++ret;
  65. if (buf[i] == '\n')
  66. {
  67. isfound = true;
  68. break;
  69. }
  70. }
  71. //如果没有找到,怀疑是mac格式,按照\r结尾解析
  72. if (!isfound)
  73. {
  74. for (int i = size - 1; i >= 0; --i)
  75. {
  76. ++ret;
  77. if (buf[i] == '\r')
  78. {
  79. isfound = true;
  80. break;
  81. }
  82. }
  83. }
  84. if (isfound)
  85. {
  86. return ret;
  87. }
  88. //说明是一个巨长的行,这种情况不是很好。直接读取了,不管是否进行了行截断
  89. return 0;
  90. }
  91. //返回第一个空闲的id,m_newFileIdList必须有序,从小到大,从0开始
  92. //序号也从0开始,notepad++是从1开始
  93. int FileManager::getNextNewFileId()
  94. {
  95. if (m_newFileIdList.isEmpty())
  96. {
  97. return 0;
  98. }
  99. int index = 0;
  100. bool isFind = false;
  101. for (int i = 0; i < m_newFileIdList.size(); ++i)
  102. {
  103. if (m_newFileIdList.at(i).index > i)
  104. {
  105. index = i;
  106. isFind = true;
  107. break;
  108. }
  109. }
  110. if (!isFind)
  111. {
  112. index = m_newFileIdList.size();
  113. }
  114. return index;
  115. }
  116. //务必要保证不能重复id,所以newnode后,必须接着调用insertNewFileNode,避免重复了
  117. void FileManager::insertNewFileNode(NewFileIdMgr node)
  118. {
  119. m_newFileIdList.append(node);
  120. std::sort(m_newFileIdList.begin(), m_newFileIdList.end(), [](NewFileIdMgr& a, NewFileIdMgr& b) {
  121. return a.index < b.index;
  122. });
  123. }
  124. //删除newfile id的节点
  125. void FileManager::delNewFileNode(int fileIndex)
  126. {
  127. for (int i = 0; i < m_newFileIdList.size(); ++i)
  128. {
  129. if (m_newFileIdList.at(i).index == fileIndex)
  130. {
  131. m_newFileIdList.removeAt(i);
  132. break;
  133. }
  134. }
  135. }
  136. //这里是以文本方式加载文件。但是可能遇到的是二进制文件,里面会做判断
  137. //二进制时hexAsk是否询问,当用户指定打开格式时,不需要询问
  138. int FileManager::loadFileDataInText(ScintillaEditView* editView, QString filePath, CODE_ID& fileTextCode, RC_LINE_FORM& lineEnd,CCNotePad * callbackObj, bool hexAsk)
  139. {
  140. QFile file(filePath);
  141. //如果文件不存在,直接返回
  142. if (!file.exists())
  143. {
  144. return -1;
  145. }
  146. QFlags<QFileDevice::Permission> power = QFile::permissions(filePath);
  147. #if 0
  148. if (!power.testFlag(QFile::ReadOwner))
  149. {
  150. //文件不能读
  151. QMessageBox::warning(nullptr, tr("Error"), tr("Open File %1 failed Can not read auth").arg(filePath));
  152. return 1;
  153. }
  154. #endif
  155. //直接以只读的方式打开,至于能不能保存,是保存时需要考虑的问题。
  156. //只需要在保存的时候获取admin权限即可
  157. QIODevice::OpenMode mode;
  158. mode = QIODevice::ExistingOnly | QIODevice::ReadOnly;
  159. #if 0
  160. if (!power.testFlag(QFile::WriteUser))
  161. {
  162. //文件不能写
  163. mode = QIODevice::ExistingOnly | QIODevice::ReadOnly;
  164. }
  165. else
  166. {
  167. mode = QIODevice::ExistingOnly | QIODevice::ReadWrite;
  168. }
  169. #endif
  170. if (!file.open(mode))
  171. {
  172. qDebug() << file.error();
  173. #ifdef Q_OS_WIN
  174. //打开失败,这里一般是权限问题导致。如果是windows,在外面申请权限后继续处理
  175. if (QFileDevice::OpenError == file.error())
  176. {
  177. if (callbackObj != nullptr)
  178. {
  179. return callbackObj->runAsAdmin(filePath);
  180. }
  181. return 1;
  182. }
  183. #endif
  184. #ifdef Q_OS_UNIX
  185. QMessageBox::warning(nullptr, tr("Error"), tr("Open File %1 failed").arg(filePath));
  186. #endif
  187. return 2;
  188. }
  189. qint64 fileSize = file.size();
  190. qint64 bufferSizeRequested = fileSize + qMin((qint64)(1 << 20), (qint64)(fileSize / 6));
  191. // As a 32bit application, we cannot allocate 2 buffer of more than INT_MAX size (it takes the whole address space)
  192. if (bufferSizeRequested > INT_MAX)
  193. {
  194. QMessageBox::warning(nullptr, tr("Error"), tr("File is too big to be opened by Notepad--"));
  195. file.close();
  196. return 3;
  197. }
  198. QList<LineFileInfo> outputLineInfoVec;
  199. int maxLineSize = 0;
  200. int charsNums = 0;
  201. bool isHexFile = false;
  202. fileTextCode = CmpareMode::scanFileOutPut(fileTextCode,filePath, outputLineInfoVec, maxLineSize, charsNums, isHexFile);
  203. if (isHexFile && hexAsk)
  204. {
  205. //检测到文件很可能是二进制文件,询问用户,是否以二进制加载
  206. int ret = QMessageBox::question(nullptr, tr("Open with Text or Hex?"), tr("The file %1 is likely to be binary. Do you want to open it in binary?").arg(filePath), tr("Hex Open"), tr("Text Open"), tr("Cancel"));
  207. if (ret == 0)
  208. {
  209. //16进制打开
  210. file.close();
  211. return 4;
  212. }
  213. else if (ret == 1)
  214. {
  215. //继续以文本打开
  216. }
  217. else
  218. {
  219. //取消,不打开
  220. file.close();
  221. return 2;
  222. }
  223. }
  224. if (maxLineSize > 0)
  225. {
  226. //int textWidth = editView->execute(SCI_TEXTWIDTH, STYLE_DEFAULT, reinterpret_cast<sptr_t>("P"));
  227. editView->execute(SCI_SETSCROLLWIDTH, maxLineSize*10);
  228. }
  229. //以第一行的换行为文本的换行符
  230. lineEnd = UNKNOWN_LINE;
  231. if (!outputLineInfoVec.isEmpty())
  232. {
  233. lineEnd = static_cast<RC_LINE_FORM>(outputLineInfoVec.at(0).lineEndFormat);
  234. }
  235. if (lineEnd == UNKNOWN_LINE)
  236. {
  237. #ifdef _WIN32
  238. lineEnd = DOS_LINE;
  239. #else
  240. lineEnd = UNIX_LINE;
  241. #endif
  242. }
  243. QString text;
  244. text.reserve(charsNums + 1);
  245. for (QList<LineFileInfo>::iterator it = outputLineInfoVec.begin(); it != outputLineInfoVec.end(); ++it)
  246. {
  247. text.append(it->unicodeStr);
  248. }
  249. file.close();
  250. //优先根据文件后缀来确定其语法风格
  251. LexerInfo lxdata = CCNotePad::getLangLexerIdByFileExt(filePath);
  252. if (lxdata.lexerId != L_TXT)
  253. {
  254. QsciLexer* lexer = editView->createLexer(lxdata.lexerId, lxdata.tagName);
  255. editView->setLexer(lexer);
  256. }
  257. else
  258. {
  259. //利用前面5行,进行一个编程语言的判断
  260. QString headContens;
  261. for (int i = 0; (i < outputLineInfoVec.size() && i < 5); ++i)
  262. {
  263. headContens.append(outputLineInfoVec.at(i).unicodeStr);
  264. }
  265. std::string headstr = headContens.toStdString();
  266. LangType _language = detectLanguageFromTextBegining((const unsigned char *)headstr.data(), headstr.length());
  267. if (_language >= 0 && _language < L_EXTERNAL)
  268. {
  269. QsciLexer* lexer = editView->createLexer(_language);
  270. editView->setLexer(lexer);
  271. }
  272. }
  273. //如果检测到时16进制文件,但是强行以二进制打开,则有限走setUtf8Text。
  274. if (!isHexFile)
  275. {
  276. editView->setText(text);
  277. }
  278. else
  279. {
  280. //这种情况,为了不编辑二进制模式,是可能只读的。
  281. if (1 == editView->setUtf8Text(text))
  282. {
  283. return 5;//只读模式
  284. }
  285. }
  286. return 0;
  287. }
  288. //加载文件,只为查找使用
  289. int FileManager::loadFileForSearch(ScintillaEditView* editView, QString filePath)
  290. {
  291. QFile file(filePath);
  292. QFlags<QFileDevice::Permission> power = QFile::permissions(filePath);
  293. if (!power.testFlag(QFile::ReadOwner))
  294. {
  295. //文件不能读
  296. return 1;
  297. }
  298. QIODevice::OpenMode mode;
  299. if (!power.testFlag(QFile::WriteOwner))
  300. {
  301. //文件不能写
  302. mode = QIODevice::ExistingOnly | QIODevice::ReadOnly;
  303. }
  304. else
  305. {
  306. mode = QIODevice::ExistingOnly | QIODevice::ReadWrite;
  307. }
  308. if (!file.open(mode))
  309. {
  310. qDebug() << file.error();
  311. return 2;
  312. }
  313. qint64 fileSize = file.size();
  314. qint64 bufferSizeRequested = fileSize + qMin((qint64)(1 << 20), (qint64)(fileSize / 6));
  315. // As a 32bit application, we cannot allocate 2 buffer of more than INT_MAX size (it takes the whole address space)
  316. if (bufferSizeRequested > INT_MAX)
  317. {
  318. file.close();
  319. return 3;
  320. }
  321. QList<LineFileInfo> outputLineInfoVec;
  322. int maxLineSize = 0;
  323. int charsNums = 0;
  324. bool isHexFile = false;
  325. CODE_ID fileTextCode = CODE_ID::UNKOWN;
  326. CmpareMode::scanFileOutPut(fileTextCode, filePath, outputLineInfoVec, maxLineSize, charsNums, isHexFile);
  327. if (isHexFile)
  328. {
  329. qDebug() << filePath;
  330. file.close();
  331. return 4;
  332. }
  333. if (maxLineSize > 0)
  334. {
  335. editView->execute(SCI_SETSCROLLWIDTH, maxLineSize * 10);
  336. }
  337. QString text;
  338. text.reserve(charsNums + 1);
  339. for (QList<LineFileInfo>::iterator it = outputLineInfoVec.begin(); it != outputLineInfoVec.end(); ++it)
  340. {
  341. text.append(it->unicodeStr);
  342. }
  343. file.close();
  344. editView->setText(text);
  345. return 0;
  346. }
  347. const int ONE_PAGE_BYTES = 4096;
  348. //加载下一页或者上一页。(二进制模式)
  349. int FileManager::loadFilePreNextPage(int dir, QString& filePath, HexFileMgr* & hexFileOut)
  350. {
  351. if (m_hexFileMgr.contains(filePath))
  352. {
  353. hexFileOut = m_hexFileMgr.value(filePath);
  354. qint64 pos = hexFileOut->fileOffset;
  355. if (dir == 1 && (pos >= 0))
  356. {
  357. //上一页
  358. pos = pos - hexFileOut->contentRealSize - ONE_PAGE_BYTES;
  359. if (pos < 0)
  360. {
  361. pos = 0;
  362. }
  363. }
  364. else if(dir == 2 && (pos < hexFileOut->fileSize))
  365. {
  366. }
  367. else
  368. {
  369. return 1;
  370. }
  371. char* buf = new char[ONE_PAGE_BYTES+1];
  372. hexFileOut->file->seek(pos);
  373. qint64 ret = hexFileOut->file->read(buf, ONE_PAGE_BYTES);
  374. if (ret <= 0)
  375. {
  376. return -1;
  377. }
  378. else
  379. {
  380. //读取成功
  381. hexFileOut->fileOffset = hexFileOut->file->pos();
  382. if (hexFileOut->contentBuf != nullptr)
  383. {
  384. delete[]hexFileOut->contentBuf;
  385. }
  386. hexFileOut->contentBuf = buf;
  387. hexFileOut->contentRealSize = ret;
  388. }
  389. return 0;
  390. }
  391. return -1;
  392. }
  393. const int ONE_PAGE_TEXT_SIZE = 200 * 1024;
  394. //加载下一页或者上一页。(文本模式)
  395. int FileManager::loadFilePreNextPage(int dir, QString& filePath, TextFileMgr* & textFileOut)
  396. {
  397. if (m_bigTxtFileMgr.contains(filePath))
  398. {
  399. textFileOut = m_bigTxtFileMgr.value(filePath);
  400. qint64 pos = textFileOut->fileOffset;
  401. int canReadSize = 0;
  402. if (dir == 1 && (pos >= 0))
  403. {
  404. //读取上一页
  405. pos = pos - textFileOut->contentRealSize - ONE_PAGE_TEXT_SIZE;
  406. if (pos < 0)
  407. {
  408. //前面的内容不足以ONE_PAGE_TEXT_SIZE字节
  409. canReadSize = textFileOut->fileOffset - textFileOut->contentRealSize;
  410. if (canReadSize <= 0)
  411. {
  412. return 1;
  413. }
  414. pos = 0;
  415. }
  416. else
  417. {
  418. canReadSize = ONE_PAGE_TEXT_SIZE;
  419. }
  420. }
  421. else if (dir == 2 && (pos < textFileOut->fileSize))
  422. {
  423. canReadSize = ONE_PAGE_TEXT_SIZE;
  424. }
  425. else
  426. {
  427. return 1;
  428. }
  429. char* buf = new char[canReadSize + 1];
  430. buf[canReadSize] = '\0';
  431. textFileOut->file->seek(pos);
  432. qint64 ret = textFileOut->file->read(buf, canReadSize);
  433. if (ret <= 0)
  434. {
  435. return -1;
  436. }
  437. else
  438. {
  439. //读取成功
  440. //如果是往后读取
  441. if (dir == 2)
  442. {
  443. //读取了1M的内容,从内容尾部往前查找,找到第一个换行符号。如果没有怎么办?说明是一个巨长的行,不妙
  444. buf[ret] = '\0';
  445. int preLineEndPos = 0;
  446. if (textFileOut->file->pos() < textFileOut->fileSize)//反之已经到尾部了,不需要往前找行首了
  447. {
  448. preLineEndPos = findLineEndPos(buf, ret);
  449. if (preLineEndPos > 0)
  450. {
  451. //给后面的字符填\0,让字符串正常结尾\0
  452. buf[ret - preLineEndPos] = '\0';
  453. }
  454. }
  455. textFileOut->fileOffset = textFileOut->file->pos() -preLineEndPos;
  456. if (preLineEndPos > 0)
  457. {
  458. //文件seek到下一行的首位置。
  459. textFileOut->file->seek(textFileOut->fileOffset);
  460. }
  461. if (textFileOut->contentBuf != nullptr)
  462. {
  463. delete[]textFileOut->contentBuf;
  464. }
  465. textFileOut->contentBuf = buf;
  466. textFileOut->contentRealSize = ret - preLineEndPos;
  467. }
  468. else if (dir == 1)
  469. {
  470. //如果是往前读取
  471. //读取了1M的内容,往内容前面往后查找,找到第一个换行符号。如果没有怎么办?说明是一个巨长的行,不妙
  472. buf[ret] = '\0';
  473. int preLineStartPos = 0;
  474. if (textFileOut->file->pos() > canReadSize)//==canReadSize说明已经在文件最前面了。不在最前面,需要
  475. {
  476. preLineStartPos = findLineStartPos(buf, ret);
  477. if (preLineStartPos > 0)
  478. {
  479. //把\n前面的内容去掉,通过内存move的方式。
  480. memmove(buf, buf+preLineStartPos,ret - preLineStartPos);
  481. buf[ret - preLineStartPos] = '\0';
  482. }
  483. }
  484. textFileOut->fileOffset = textFileOut->file->pos();
  485. if (textFileOut->contentBuf != nullptr)
  486. {
  487. delete[]textFileOut->contentBuf;
  488. }
  489. textFileOut->contentBuf = buf;
  490. textFileOut->contentRealSize = ret - preLineStartPos;
  491. }
  492. }
  493. return 0;
  494. }
  495. return -1;
  496. }
  497. //从指定地址开始加载文件
  498. int FileManager::loadFileFromAddr(QString filePath, qint64 addr, HexFileMgr* & hexFileOut)
  499. {
  500. if (m_hexFileMgr.contains(filePath))
  501. {
  502. hexFileOut = m_hexFileMgr.value(filePath);
  503. //超过文件大小
  504. if (addr < 0 || addr >= hexFileOut->fileSize)
  505. {
  506. return -2;
  507. }
  508. //4K对齐
  509. addr &= 0xfffffffffff0;
  510. char* buf = new char[ONE_PAGE_BYTES + 1];
  511. hexFileOut->file->seek(addr);
  512. qint64 ret = hexFileOut->file->read(buf, ONE_PAGE_BYTES);
  513. if (ret <= 0)
  514. {
  515. return -1;
  516. }
  517. else
  518. {
  519. //读取成功
  520. hexFileOut->fileOffset = hexFileOut->file->pos();
  521. if (hexFileOut->contentBuf != nullptr)
  522. {
  523. delete[]hexFileOut->contentBuf;
  524. }
  525. hexFileOut->contentBuf = buf;
  526. hexFileOut->contentRealSize = ret;
  527. }
  528. return 0;
  529. }
  530. return -1;
  531. }
  532. //从指定地址开始加载文本文件
  533. int FileManager::loadFileFromAddr(QString filePath, qint64 addr, TextFileMgr* & textFileOut)
  534. {
  535. if (m_bigTxtFileMgr.contains(filePath))
  536. {
  537. textFileOut = m_bigTxtFileMgr.value(filePath);
  538. //超过文件大小
  539. if (addr < 0 || addr >= textFileOut->fileSize)
  540. {
  541. return -2;
  542. }
  543. char* buf = new char[ONE_PAGE_TEXT_SIZE + 1];
  544. buf[ONE_PAGE_TEXT_SIZE] = '\0';
  545. textFileOut->file->seek(addr);
  546. qint64 ret = textFileOut->file->read(buf, ONE_PAGE_TEXT_SIZE);
  547. if (ret <= 0)//-1是出错。0也是没有读到
  548. {
  549. return -1;
  550. }
  551. else
  552. {
  553. int preLineEndPos = 0;
  554. buf[ret] = '\0';
  555. if (textFileOut->file->pos() < textFileOut->fileSize)//反之已经到尾部了,不需要往前找行了
  556. {
  557. preLineEndPos = findLineEndPos(buf, ret);
  558. if (preLineEndPos > 0)
  559. {
  560. //给后面的字符填\0,让字符串正常结尾\0
  561. buf[ret - preLineEndPos] = '\0';
  562. }
  563. }
  564. int preLineStartPos = findLineStartPos(buf, ret);
  565. if (preLineStartPos > 0 && preLineStartPos < ret) //preLineStartPos如果大于ret,则全部都被跳过了,不会显示,是个特例
  566. {
  567. memmove(buf, buf + preLineStartPos, ret - preLineStartPos);
  568. buf[ret - preLineStartPos] = '\0';
  569. }
  570. else
  571. {
  572. //如果没做调整,则后续不需要偏移,这里必须preLineStartPos赋0值
  573. preLineStartPos = 0;
  574. }
  575. //只需要文件调到上一行的行位即可。
  576. textFileOut->fileOffset = textFileOut->file->pos() - preLineEndPos;
  577. if (preLineEndPos > 0)
  578. {
  579. //文件seek到下一行的首位置。
  580. textFileOut->file->seek(textFileOut->fileOffset);
  581. }
  582. if (textFileOut->contentBuf != nullptr)
  583. {
  584. delete[]textFileOut->contentBuf;
  585. }
  586. textFileOut->contentBuf = buf;
  587. textFileOut->contentRealSize = ret - preLineEndPos - preLineStartPos;
  588. }
  589. return 0;
  590. }
  591. return -1;
  592. }
  593. //加载二进制文件。从curPos开始,每行16个byte,每次读取64行,一共1024个byte
  594. bool FileManager::loadFileData(QString filePath, HexFileMgr* & hexFileOut)
  595. {
  596. QFile *file = new QFile(filePath);
  597. if (!file->open(QIODevice::ReadOnly | QIODevice::ExistingOnly))
  598. {
  599. return false;
  600. }
  601. //小于10k的文件一次性全部读取完毕
  602. const int LITTLE_FILE_MAX = 10240;
  603. int readBytes = 0;
  604. if (file->size() <= LITTLE_FILE_MAX)
  605. {
  606. readBytes = LITTLE_FILE_MAX;
  607. }
  608. else
  609. {
  610. //对于大于10K的文件,每次只读4K
  611. readBytes = ONE_PAGE_BYTES;
  612. }
  613. char* buf = new char[readBytes];
  614. qint64 ret = file->read(buf, readBytes);
  615. if (ret == -1)
  616. {
  617. //错误
  618. file->close();
  619. delete file;
  620. return false;
  621. }
  622. else
  623. {
  624. HexFileMgr* hexFile = nullptr;
  625. if (!m_hexFileMgr.contains(filePath))
  626. {
  627. hexFile = new HexFileMgr();
  628. hexFile->filePath = filePath;
  629. hexFile->file = file;
  630. hexFile->fileOffset = file->pos();
  631. hexFile->fileSize = file->size();
  632. hexFile->contentBuf = buf;
  633. hexFile->contentRealSize = ret;
  634. m_hexFileMgr.insert(filePath, hexFile);
  635. }
  636. else
  637. {
  638. //理论上这里永远不走
  639. hexFile = m_hexFileMgr.value(filePath);
  640. hexFile->fileOffset = file->pos();
  641. hexFile->contentBuf = buf;
  642. hexFile->contentRealSize = ret;
  643. }
  644. hexFileOut = hexFile;
  645. return true;
  646. }
  647. return false;
  648. }
  649. //加载大文本文件。从0开始读取ONE_PAGE_TEXT_SIZE 500K的内容
  650. bool FileManager::loadFileData(QString filePath, TextFileMgr* & textFileOut)
  651. {
  652. QFile *file = new QFile(filePath);
  653. if (!file->open(QIODevice::ReadOnly | QIODevice::ExistingOnly))
  654. {
  655. return false;
  656. }
  657. int readBytes = ONE_PAGE_TEXT_SIZE;
  658. char* buf = new char[ONE_PAGE_TEXT_SIZE+1];
  659. buf[ONE_PAGE_TEXT_SIZE] = '\0';
  660. qint64 ret = file->read(buf, readBytes);
  661. if (ret <= 0)
  662. {
  663. //错误
  664. file->close();
  665. delete file;
  666. return false;
  667. }
  668. else
  669. {
  670. //读取了1M的内容,从尾部往找,找到第一个换行符号。如果没有怎么办?说明是一个巨长的行,不妙
  671. buf[ret] = '\0';
  672. int preLineEndPos = findLineEndPos(buf,ret);
  673. if (preLineEndPos > 0)
  674. {
  675. //给后面的字符填\0,让字符串正常结尾\0
  676. buf[ret - preLineEndPos] = '\0';
  677. }
  678. TextFileMgr* txtFile = nullptr;
  679. if (!m_bigTxtFileMgr.contains(filePath))
  680. {
  681. txtFile = new TextFileMgr();
  682. txtFile->filePath = filePath;
  683. txtFile->file = file;
  684. txtFile->fileOffset = file->pos() - preLineEndPos;
  685. if (preLineEndPos > 0)
  686. {
  687. //文件seek到下一行的首位置。下次读的时候,头部肯定是一行的行首啦
  688. file->seek(txtFile->fileOffset);
  689. }
  690. txtFile->fileSize = file->size();
  691. txtFile->contentBuf = buf;
  692. txtFile->contentRealSize = ret - preLineEndPos;
  693. m_bigTxtFileMgr.insert(filePath, txtFile);
  694. }
  695. else
  696. {
  697. //理论上这里永远不走
  698. assert(false);
  699. txtFile = m_bigTxtFileMgr.value(filePath);
  700. txtFile->fileOffset = file->pos();
  701. txtFile->contentBuf = buf;
  702. txtFile->contentRealSize = ret;
  703. }
  704. textFileOut = txtFile;
  705. return true;
  706. }
  707. return false;
  708. }
  709. HexFileMgr * FileManager::getHexFileHand(QString filepath)
  710. {
  711. if (m_hexFileMgr.contains(filepath))
  712. {
  713. return m_hexFileMgr.value(filepath);
  714. }
  715. return nullptr;
  716. }
  717. void FileManager::closeHexFileHand(QString filepath)
  718. {
  719. if (m_hexFileMgr.contains(filepath))
  720. {
  721. HexFileMgr* v = m_hexFileMgr.value(filepath);
  722. v->destory();
  723. delete v;
  724. m_hexFileMgr.remove(filepath);
  725. }
  726. }
  727. void FileManager::closeBigTextFileHand(QString filepath)
  728. {
  729. if (m_bigTxtFileMgr.contains(filepath))
  730. {
  731. TextFileMgr* v = m_bigTxtFileMgr.value(filepath);
  732. v->destory();
  733. delete v;
  734. m_bigTxtFileMgr.remove(filepath);
  735. }
  736. }
  737. //检查文件的编程语言
  738. LangType FileManager::detectLanguageFromTextBegining(const unsigned char *data, size_t dataLen)
  739. {
  740. struct FirstLineLanguages
  741. {
  742. std::string pattern;
  743. LangType lang;
  744. };
  745. // Is the buffer at least the size of a BOM?
  746. if (dataLen <= 3)
  747. return L_TXT;
  748. // Eliminate BOM if present
  749. size_t i = 0;
  750. if ((data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF) || // UTF8 BOM
  751. (data[0] == 0xFE && data[1] == 0xFF && data[2] == 0x00) || // UTF16 BE BOM
  752. (data[0] == 0xFF && data[1] == 0xFE && data[2] == 0x00)) // UTF16 LE BOM
  753. i += 3;
  754. // Skip any space-like char
  755. for (; i < dataLen; ++i)
  756. {
  757. if (data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r')
  758. break;
  759. }
  760. // Create the buffer to need to test
  761. const size_t longestLength = 40; // shebangs can be large
  762. std::string buf2Test = std::string((const char *)data + i, longestLength);
  763. // Is there a \r or \n in the buffer? If so, truncate it
  764. auto cr = buf2Test.find("\r");
  765. auto nl = buf2Test.find("\n");
  766. auto crnl = qMin(cr, nl);
  767. if (crnl != std::string::npos && crnl < longestLength)
  768. buf2Test = std::string((const char *)data + i, crnl);
  769. // First test for a Unix-like Shebang
  770. // See https://en.wikipedia.org/wiki/Shebang_%28Unix%29 for more details about Shebang
  771. std::string shebang = "#!";
  772. size_t foundPos = buf2Test.find(shebang);
  773. if (foundPos == 0)
  774. {
  775. // Make a list of the most commonly used languages
  776. const size_t NB_SHEBANG_LANGUAGES = 7;
  777. FirstLineLanguages ShebangLangs[NB_SHEBANG_LANGUAGES] = {
  778. { "sh", L_BASH },
  779. { "python", L_PYTHON },
  780. { "perl", L_PERL },
  781. { "php", L_PHP },
  782. { "ruby", L_RUBY },
  783. { "node", L_JAVASCRIPT },
  784. { "Makefile", L_MAKEFILE}
  785. };
  786. // Go through the list of languages
  787. for (i = 0; i < NB_SHEBANG_LANGUAGES; ++i)
  788. {
  789. if (buf2Test.find(ShebangLangs[i].pattern) != std::string::npos)
  790. {
  791. return ShebangLangs[i].lang;
  792. }
  793. }
  794. // Unrecognized shebang (there is always room for improvement ;-)
  795. return L_TXT;
  796. }
  797. // Are there any other patterns we know off?
  798. const size_t NB_FIRST_LINE_LANGUAGES = 5;
  799. FirstLineLanguages languages[NB_FIRST_LINE_LANGUAGES] = {
  800. { "<?xml", L_XML },
  801. { "<?php", L_PHP },
  802. { "<html", L_HTML },
  803. { "<!DOCTYPE html", L_HTML },
  804. { "<?", L_PHP } // MUST be after "<?php" and "<?xml" to get the result as accurate as possible
  805. };
  806. for (i = 0; i < NB_FIRST_LINE_LANGUAGES; ++i)
  807. {
  808. foundPos = buf2Test.find(languages[i].pattern);
  809. if (foundPos == 0)
  810. {
  811. return languages[i].lang;
  812. }
  813. }
  814. // Unrecognized first line, we assume it is a text file for now
  815. return L_UNKNOWN;
  816. }