filemanager.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  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. editView->execute(SCI_SETSCROLLWIDTH, maxLineSize*10);
  227. }
  228. //以第一行的换行为文本的换行符
  229. lineEnd = UNKNOWN_LINE;
  230. if (!outputLineInfoVec.isEmpty())
  231. {
  232. lineEnd = static_cast<RC_LINE_FORM>(outputLineInfoVec.at(0).lineEndFormat);
  233. }
  234. if (lineEnd == UNKNOWN_LINE)
  235. {
  236. #ifdef _WIN32
  237. lineEnd = DOS_LINE;
  238. #else
  239. lineEnd = UNIX_LINE;
  240. #endif
  241. }
  242. QString text;
  243. text.reserve(charsNums + 1);
  244. for (QList<LineFileInfo>::iterator it = outputLineInfoVec.begin(); it != outputLineInfoVec.end(); ++it)
  245. {
  246. text.append(it->unicodeStr);
  247. }
  248. file.close();
  249. //利用前面5行,进行一个编程语言的判断
  250. QString headContens;
  251. for (int i = 0; (i < outputLineInfoVec.size() && i < 5); ++i)
  252. {
  253. headContens.append(outputLineInfoVec.at(i).unicodeStr);
  254. }
  255. std::string headstr = headContens.toStdString();
  256. LangType _language = detectLanguageFromTextBegining((const unsigned char *)headstr.data(), headstr.length());
  257. if (_language>= 0 && _language < L_EXTERNAL)
  258. {
  259. //editView->execute(SCI_SETLEXER, ScintillaEditView::langNames[_language].lexerID);
  260. QsciLexer* lexer = editView->createLexer(_language);
  261. editView->setLexer(lexer);
  262. }
  263. //如果检测到时16进制文件,但是强行以二进制打开,则有限走setUtf8Text。
  264. if (!isHexFile)
  265. {
  266. editView->setText(text);
  267. }
  268. else
  269. {
  270. //这种情况,为了不编辑二进制模式,是可能只读的。
  271. if (1 == editView->setUtf8Text(text))
  272. {
  273. return 5;//只读模式
  274. }
  275. }
  276. return 0;
  277. }
  278. //加载文件,只为查找使用
  279. int FileManager::loadFileForSearch(ScintillaEditView* editView, QString filePath)
  280. {
  281. QFile file(filePath);
  282. QFlags<QFileDevice::Permission> power = QFile::permissions(filePath);
  283. if (!power.testFlag(QFile::ReadOwner))
  284. {
  285. //文件不能读
  286. return 1;
  287. }
  288. QIODevice::OpenMode mode;
  289. if (!power.testFlag(QFile::WriteOwner))
  290. {
  291. //文件不能写
  292. mode = QIODevice::ExistingOnly | QIODevice::ReadOnly;
  293. }
  294. else
  295. {
  296. mode = QIODevice::ExistingOnly | QIODevice::ReadWrite;
  297. }
  298. if (!file.open(mode))
  299. {
  300. qDebug() << file.error();
  301. return 2;
  302. }
  303. qint64 fileSize = file.size();
  304. qint64 bufferSizeRequested = fileSize + qMin((qint64)(1 << 20), (qint64)(fileSize / 6));
  305. // As a 32bit application, we cannot allocate 2 buffer of more than INT_MAX size (it takes the whole address space)
  306. if (bufferSizeRequested > INT_MAX)
  307. {
  308. file.close();
  309. return 3;
  310. }
  311. QList<LineFileInfo> outputLineInfoVec;
  312. int maxLineSize = 0;
  313. int charsNums = 0;
  314. bool isHexFile = false;
  315. CODE_ID fileTextCode = CODE_ID::UNKOWN;
  316. CmpareMode::scanFileOutPut(fileTextCode, filePath, outputLineInfoVec, maxLineSize, charsNums, isHexFile);
  317. if (isHexFile)
  318. {
  319. qDebug() << filePath;
  320. file.close();
  321. return 4;
  322. }
  323. if (maxLineSize > 0)
  324. {
  325. editView->execute(SCI_SETSCROLLWIDTH, maxLineSize * 10);
  326. }
  327. QString text;
  328. text.reserve(charsNums + 1);
  329. for (QList<LineFileInfo>::iterator it = outputLineInfoVec.begin(); it != outputLineInfoVec.end(); ++it)
  330. {
  331. text.append(it->unicodeStr);
  332. }
  333. file.close();
  334. editView->setText(text);
  335. return 0;
  336. }
  337. const int ONE_PAGE_BYTES = 4096;
  338. //加载下一页或者上一页。(二进制模式)
  339. int FileManager::loadFilePreNextPage(int dir, QString& filePath, HexFileMgr* & hexFileOut)
  340. {
  341. if (m_hexFileMgr.contains(filePath))
  342. {
  343. hexFileOut = m_hexFileMgr.value(filePath);
  344. qint64 pos = hexFileOut->fileOffset;
  345. if (dir == 1 && (pos >= 0))
  346. {
  347. //上一页
  348. pos = pos - hexFileOut->contentRealSize - ONE_PAGE_BYTES;
  349. if (pos < 0)
  350. {
  351. pos = 0;
  352. }
  353. }
  354. else if(dir == 2 && (pos < hexFileOut->fileSize))
  355. {
  356. }
  357. else
  358. {
  359. return 1;
  360. }
  361. char* buf = new char[ONE_PAGE_BYTES+1];
  362. hexFileOut->file->seek(pos);
  363. qint64 ret = hexFileOut->file->read(buf, ONE_PAGE_BYTES);
  364. if (ret <= 0)
  365. {
  366. return -1;
  367. }
  368. else
  369. {
  370. //读取成功
  371. hexFileOut->fileOffset = hexFileOut->file->pos();
  372. if (hexFileOut->contentBuf != nullptr)
  373. {
  374. delete[]hexFileOut->contentBuf;
  375. }
  376. hexFileOut->contentBuf = buf;
  377. hexFileOut->contentRealSize = ret;
  378. }
  379. return 0;
  380. }
  381. return -1;
  382. }
  383. const int ONE_PAGE_TEXT_SIZE = 200 * 1024;
  384. //加载下一页或者上一页。(文本模式)
  385. int FileManager::loadFilePreNextPage(int dir, QString& filePath, TextFileMgr* & textFileOut)
  386. {
  387. if (m_bigTxtFileMgr.contains(filePath))
  388. {
  389. textFileOut = m_bigTxtFileMgr.value(filePath);
  390. qint64 pos = textFileOut->fileOffset;
  391. int canReadSize = 0;
  392. if (dir == 1 && (pos >= 0))
  393. {
  394. //读取上一页
  395. pos = pos - textFileOut->contentRealSize - ONE_PAGE_TEXT_SIZE;
  396. if (pos < 0)
  397. {
  398. //前面的内容不足以ONE_PAGE_TEXT_SIZE字节
  399. canReadSize = textFileOut->fileOffset - textFileOut->contentRealSize;
  400. if (canReadSize <= 0)
  401. {
  402. return 1;
  403. }
  404. pos = 0;
  405. }
  406. else
  407. {
  408. canReadSize = ONE_PAGE_TEXT_SIZE;
  409. }
  410. }
  411. else if (dir == 2 && (pos < textFileOut->fileSize))
  412. {
  413. canReadSize = ONE_PAGE_TEXT_SIZE;
  414. }
  415. else
  416. {
  417. return 1;
  418. }
  419. char* buf = new char[canReadSize + 1];
  420. buf[canReadSize] = '\0';
  421. textFileOut->file->seek(pos);
  422. qint64 ret = textFileOut->file->read(buf, canReadSize);
  423. if (ret <= 0)
  424. {
  425. return -1;
  426. }
  427. else
  428. {
  429. //读取成功
  430. //如果是往后读取
  431. if (dir == 2)
  432. {
  433. //读取了1M的内容,从内容尾部往前查找,找到第一个换行符号。如果没有怎么办?说明是一个巨长的行,不妙
  434. buf[ret] = '\0';
  435. int preLineEndPos = 0;
  436. if (textFileOut->file->pos() < textFileOut->fileSize)//反之已经到尾部了,不需要往前找行首了
  437. {
  438. preLineEndPos = findLineEndPos(buf, ret);
  439. if (preLineEndPos > 0)
  440. {
  441. //给后面的字符填\0,让字符串正常结尾\0
  442. buf[ret - preLineEndPos] = '\0';
  443. }
  444. }
  445. textFileOut->fileOffset = textFileOut->file->pos() -preLineEndPos;
  446. if (preLineEndPos > 0)
  447. {
  448. //文件seek到下一行的首位置。
  449. textFileOut->file->seek(textFileOut->fileOffset);
  450. }
  451. if (textFileOut->contentBuf != nullptr)
  452. {
  453. delete[]textFileOut->contentBuf;
  454. }
  455. textFileOut->contentBuf = buf;
  456. textFileOut->contentRealSize = ret - preLineEndPos;
  457. }
  458. else if (dir == 1)
  459. {
  460. //如果是往前读取
  461. //读取了1M的内容,往内容前面往后查找,找到第一个换行符号。如果没有怎么办?说明是一个巨长的行,不妙
  462. buf[ret] = '\0';
  463. int preLineStartPos = 0;
  464. if (textFileOut->file->pos() > canReadSize)//==canReadSize说明已经在文件最前面了。不在最前面,需要
  465. {
  466. preLineStartPos = findLineStartPos(buf, ret);
  467. if (preLineStartPos > 0)
  468. {
  469. //把\n前面的内容去掉,通过内存move的方式。
  470. memmove(buf, buf+preLineStartPos,ret - preLineStartPos);
  471. buf[ret - preLineStartPos] = '\0';
  472. }
  473. }
  474. textFileOut->fileOffset = textFileOut->file->pos();
  475. if (textFileOut->contentBuf != nullptr)
  476. {
  477. delete[]textFileOut->contentBuf;
  478. }
  479. textFileOut->contentBuf = buf;
  480. textFileOut->contentRealSize = ret - preLineStartPos;
  481. }
  482. }
  483. return 0;
  484. }
  485. return -1;
  486. }
  487. //从指定地址开始加载文件
  488. int FileManager::loadFileFromAddr(QString filePath, qint64 addr, HexFileMgr* & hexFileOut)
  489. {
  490. if (m_hexFileMgr.contains(filePath))
  491. {
  492. hexFileOut = m_hexFileMgr.value(filePath);
  493. //超过文件大小
  494. if (addr < 0 || addr >= hexFileOut->fileSize)
  495. {
  496. return -2;
  497. }
  498. //4K对齐
  499. addr &= 0xfffffffffff0;
  500. char* buf = new char[ONE_PAGE_BYTES + 1];
  501. hexFileOut->file->seek(addr);
  502. qint64 ret = hexFileOut->file->read(buf, ONE_PAGE_BYTES);
  503. if (ret <= 0)
  504. {
  505. return -1;
  506. }
  507. else
  508. {
  509. //读取成功
  510. hexFileOut->fileOffset = hexFileOut->file->pos();
  511. if (hexFileOut->contentBuf != nullptr)
  512. {
  513. delete[]hexFileOut->contentBuf;
  514. }
  515. hexFileOut->contentBuf = buf;
  516. hexFileOut->contentRealSize = ret;
  517. }
  518. return 0;
  519. }
  520. return -1;
  521. }
  522. //从指定地址开始加载文本文件
  523. int FileManager::loadFileFromAddr(QString filePath, qint64 addr, TextFileMgr* & textFileOut)
  524. {
  525. if (m_bigTxtFileMgr.contains(filePath))
  526. {
  527. textFileOut = m_bigTxtFileMgr.value(filePath);
  528. //超过文件大小
  529. if (addr < 0 || addr >= textFileOut->fileSize)
  530. {
  531. return -2;
  532. }
  533. char* buf = new char[ONE_PAGE_TEXT_SIZE + 1];
  534. buf[ONE_PAGE_TEXT_SIZE] = '\0';
  535. textFileOut->file->seek(addr);
  536. qint64 ret = textFileOut->file->read(buf, ONE_PAGE_TEXT_SIZE);
  537. if (ret <= 0)//-1是出错。0也是没有读到
  538. {
  539. return -1;
  540. }
  541. else
  542. {
  543. int preLineEndPos = 0;
  544. buf[ret] = '\0';
  545. if (textFileOut->file->pos() < textFileOut->fileSize)//反之已经到尾部了,不需要往前找行了
  546. {
  547. preLineEndPos = findLineEndPos(buf, ret);
  548. if (preLineEndPos > 0)
  549. {
  550. //给后面的字符填\0,让字符串正常结尾\0
  551. buf[ret - preLineEndPos] = '\0';
  552. }
  553. }
  554. int preLineStartPos = findLineStartPos(buf, ret);
  555. if (preLineStartPos > 0 && preLineStartPos < ret) //preLineStartPos如果大于ret,则全部都被跳过了,不会显示,是个特例
  556. {
  557. memmove(buf, buf + preLineStartPos, ret - preLineStartPos);
  558. buf[ret - preLineStartPos] = '\0';
  559. }
  560. else
  561. {
  562. //如果没做调整,则后续不需要偏移,这里必须preLineStartPos赋0值
  563. preLineStartPos = 0;
  564. }
  565. //只需要文件调到上一行的行位即可。
  566. textFileOut->fileOffset = textFileOut->file->pos() - preLineEndPos;
  567. if (preLineEndPos > 0)
  568. {
  569. //文件seek到下一行的首位置。
  570. textFileOut->file->seek(textFileOut->fileOffset);
  571. }
  572. if (textFileOut->contentBuf != nullptr)
  573. {
  574. delete[]textFileOut->contentBuf;
  575. }
  576. textFileOut->contentBuf = buf;
  577. textFileOut->contentRealSize = ret - preLineEndPos - preLineStartPos;
  578. }
  579. return 0;
  580. }
  581. return -1;
  582. }
  583. //加载二进制文件。从curPos开始,每行16个byte,每次读取64行,一共1024个byte
  584. bool FileManager::loadFileData(QString filePath, HexFileMgr* & hexFileOut)
  585. {
  586. QFile *file = new QFile(filePath);
  587. if (!file->open(QIODevice::ReadOnly | QIODevice::ExistingOnly))
  588. {
  589. return false;
  590. }
  591. //小于10k的文件一次性全部读取完毕
  592. const int LITTLE_FILE_MAX = 10240;
  593. int readBytes = 0;
  594. if (file->size() <= LITTLE_FILE_MAX)
  595. {
  596. readBytes = LITTLE_FILE_MAX;
  597. }
  598. else
  599. {
  600. //对于大于10K的文件,每次只读4K
  601. readBytes = ONE_PAGE_BYTES;
  602. }
  603. char* buf = new char[readBytes];
  604. qint64 ret = file->read(buf, readBytes);
  605. if (ret == -1)
  606. {
  607. //错误
  608. file->close();
  609. delete file;
  610. return false;
  611. }
  612. else
  613. {
  614. HexFileMgr* hexFile = nullptr;
  615. if (!m_hexFileMgr.contains(filePath))
  616. {
  617. hexFile = new HexFileMgr();
  618. hexFile->filePath = filePath;
  619. hexFile->file = file;
  620. hexFile->fileOffset = file->pos();
  621. hexFile->fileSize = file->size();
  622. hexFile->contentBuf = buf;
  623. hexFile->contentRealSize = ret;
  624. m_hexFileMgr.insert(filePath, hexFile);
  625. }
  626. else
  627. {
  628. //理论上这里永远不走
  629. hexFile = m_hexFileMgr.value(filePath);
  630. hexFile->fileOffset = file->pos();
  631. hexFile->contentBuf = buf;
  632. hexFile->contentRealSize = ret;
  633. }
  634. hexFileOut = hexFile;
  635. return true;
  636. }
  637. return false;
  638. }
  639. //加载大文本文件。从0开始读取ONE_PAGE_TEXT_SIZE 500K的内容
  640. bool FileManager::loadFileData(QString filePath, TextFileMgr* & textFileOut)
  641. {
  642. QFile *file = new QFile(filePath);
  643. if (!file->open(QIODevice::ReadOnly | QIODevice::ExistingOnly))
  644. {
  645. return false;
  646. }
  647. int readBytes = ONE_PAGE_TEXT_SIZE;
  648. char* buf = new char[ONE_PAGE_TEXT_SIZE+1];
  649. buf[ONE_PAGE_TEXT_SIZE] = '\0';
  650. qint64 ret = file->read(buf, readBytes);
  651. if (ret <= 0)
  652. {
  653. //错误
  654. file->close();
  655. delete file;
  656. return false;
  657. }
  658. else
  659. {
  660. //读取了1M的内容,从尾部往找,找到第一个换行符号。如果没有怎么办?说明是一个巨长的行,不妙
  661. buf[ret] = '\0';
  662. int preLineEndPos = findLineEndPos(buf,ret);
  663. if (preLineEndPos > 0)
  664. {
  665. //给后面的字符填\0,让字符串正常结尾\0
  666. buf[ret - preLineEndPos] = '\0';
  667. }
  668. TextFileMgr* txtFile = nullptr;
  669. if (!m_bigTxtFileMgr.contains(filePath))
  670. {
  671. txtFile = new TextFileMgr();
  672. txtFile->filePath = filePath;
  673. txtFile->file = file;
  674. txtFile->fileOffset = file->pos() - preLineEndPos;
  675. if (preLineEndPos > 0)
  676. {
  677. //文件seek到下一行的首位置。下次读的时候,头部肯定是一行的行首啦
  678. file->seek(txtFile->fileOffset);
  679. }
  680. txtFile->fileSize = file->size();
  681. txtFile->contentBuf = buf;
  682. txtFile->contentRealSize = ret - preLineEndPos;
  683. m_bigTxtFileMgr.insert(filePath, txtFile);
  684. }
  685. else
  686. {
  687. //理论上这里永远不走
  688. assert(false);
  689. txtFile = m_bigTxtFileMgr.value(filePath);
  690. txtFile->fileOffset = file->pos();
  691. txtFile->contentBuf = buf;
  692. txtFile->contentRealSize = ret;
  693. }
  694. textFileOut = txtFile;
  695. return true;
  696. }
  697. return false;
  698. }
  699. HexFileMgr * FileManager::getHexFileHand(QString filepath)
  700. {
  701. if (m_hexFileMgr.contains(filepath))
  702. {
  703. return m_hexFileMgr.value(filepath);
  704. }
  705. return nullptr;
  706. }
  707. void FileManager::closeHexFileHand(QString filepath)
  708. {
  709. if (m_hexFileMgr.contains(filepath))
  710. {
  711. HexFileMgr* v = m_hexFileMgr.value(filepath);
  712. v->destory();
  713. delete v;
  714. m_hexFileMgr.remove(filepath);
  715. }
  716. }
  717. void FileManager::closeBigTextFileHand(QString filepath)
  718. {
  719. if (m_bigTxtFileMgr.contains(filepath))
  720. {
  721. TextFileMgr* v = m_bigTxtFileMgr.value(filepath);
  722. v->destory();
  723. delete v;
  724. m_bigTxtFileMgr.remove(filepath);
  725. }
  726. }
  727. //检查文件的编程语言
  728. LangType FileManager::detectLanguageFromTextBegining(const unsigned char *data, size_t dataLen)
  729. {
  730. struct FirstLineLanguages
  731. {
  732. std::string pattern;
  733. LangType lang;
  734. };
  735. // Is the buffer at least the size of a BOM?
  736. if (dataLen <= 3)
  737. return L_TXT;
  738. // Eliminate BOM if present
  739. size_t i = 0;
  740. if ((data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF) || // UTF8 BOM
  741. (data[0] == 0xFE && data[1] == 0xFF && data[2] == 0x00) || // UTF16 BE BOM
  742. (data[0] == 0xFF && data[1] == 0xFE && data[2] == 0x00)) // UTF16 LE BOM
  743. i += 3;
  744. // Skip any space-like char
  745. for (; i < dataLen; ++i)
  746. {
  747. if (data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r')
  748. break;
  749. }
  750. // Create the buffer to need to test
  751. const size_t longestLength = 40; // shebangs can be large
  752. std::string buf2Test = std::string((const char *)data + i, longestLength);
  753. // Is there a \r or \n in the buffer? If so, truncate it
  754. auto cr = buf2Test.find("\r");
  755. auto nl = buf2Test.find("\n");
  756. auto crnl = qMin(cr, nl);
  757. if (crnl != std::string::npos && crnl < longestLength)
  758. buf2Test = std::string((const char *)data + i, crnl);
  759. // First test for a Unix-like Shebang
  760. // See https://en.wikipedia.org/wiki/Shebang_%28Unix%29 for more details about Shebang
  761. std::string shebang = "#!";
  762. size_t foundPos = buf2Test.find(shebang);
  763. if (foundPos == 0)
  764. {
  765. // Make a list of the most commonly used languages
  766. const size_t NB_SHEBANG_LANGUAGES = 7;
  767. FirstLineLanguages ShebangLangs[NB_SHEBANG_LANGUAGES] = {
  768. { "sh", L_BASH },
  769. { "python", L_PYTHON },
  770. { "perl", L_PERL },
  771. { "php", L_PHP },
  772. { "ruby", L_RUBY },
  773. { "node", L_JAVASCRIPT },
  774. { "Makefile", L_MAKEFILE}
  775. };
  776. // Go through the list of languages
  777. for (i = 0; i < NB_SHEBANG_LANGUAGES; ++i)
  778. {
  779. if (buf2Test.find(ShebangLangs[i].pattern) != std::string::npos)
  780. {
  781. return ShebangLangs[i].lang;
  782. }
  783. }
  784. // Unrecognized shebang (there is always room for improvement ;-)
  785. return L_TXT;
  786. }
  787. // Are there any other patterns we know off?
  788. const size_t NB_FIRST_LINE_LANGUAGES = 5;
  789. FirstLineLanguages languages[NB_FIRST_LINE_LANGUAGES] = {
  790. { "<?xml", L_XML },
  791. { "<?php", L_PHP },
  792. { "<html", L_HTML },
  793. { "<!DOCTYPE html", L_HTML },
  794. { "<?", L_PHP } // MUST be after "<?php" and "<?xml" to get the result as accurate as possible
  795. };
  796. for (i = 0; i < NB_FIRST_LINE_LANGUAGES; ++i)
  797. {
  798. foundPos = buf2Test.find(languages[i].pattern);
  799. if (foundPos == 0)
  800. {
  801. return languages[i].lang;
  802. }
  803. }
  804. // Unrecognized first line, we assume it is a text file for now
  805. return L_UNKNOWN;
  806. }