filemanager.cpp 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328
  1. #include "filemanager.h"
  2. #include "scintillaeditview.h"
  3. #include "scintillahexeditview.h"
  4. #include "CmpareMode.h"
  5. #include "ccnotepad.h"
  6. #include "progresswin.h"
  7. #include <QMessageBox>
  8. #include <QFile>
  9. #include <QtGlobal>
  10. #include <qscilexer.h>
  11. FileManager::FileManager():m_lastErrorCode(NONE_ERROR)
  12. {
  13. }
  14. FileManager::~FileManager()
  15. {
  16. }
  17. ScintillaEditView* FileManager::newEmptyDocument(bool isBigText)
  18. {
  19. ScintillaEditView* pEdit = new ScintillaEditView(nullptr, isBigText);
  20. return pEdit;
  21. }
  22. ScintillaHexEditView* FileManager::newEmptyHexDocument()
  23. {
  24. ScintillaHexEditView* pEdit = new ScintillaHexEditView(nullptr);
  25. return pEdit;
  26. }
  27. //从尾部找前面的换行符号。返回的是需要回溯的个数
  28. //注意如果是LE编码,字节流是\n\0的格式。从尾部往前回溯,找到\n,要回退1个\0。\n\0是一个整体,不能分割开
  29. //20230201发现一个bug,在LE模式下,不能单纯用\n做换行识别。因为发现其它字符也存在\n,必须要完整以\n\0才能确定是换行。
  30. //同样发现BE模式下,是\0\n的格式,也不能单独使用\n做换行识别,因为发现其他字符也存在\n,必须要完整以\0\n才能确定是换行
  31. int findLineEndPos(const char* buf, int size, CODE_ID code = UNKOWN)
  32. {
  33. int ret = 0;
  34. bool isfound = false;
  35. for (int i = size - 1; i >= 0; --i)
  36. {
  37. if (buf[i] == '\n')
  38. {
  39. ////如果是LE,还要确定\n的下一个是否是\0
  40. if ((code == UNICODE_LE) && ((i != size -1) && (buf[i+1] != '\0')))
  41. {
  42. ++ret;
  43. continue;
  44. }
  45. ////如果是BE,还要确定\n的前一个是否是\0
  46. if ((code == UNICODE_BE) && ((i != 0) && (buf[i - 1] != '\0')))
  47. {
  48. ++ret;
  49. continue;
  50. }
  51. isfound = true;
  52. break;
  53. }
  54. ++ret;
  55. }
  56. //如果没有找到,怀疑是mac格式,按照\r结尾解析
  57. if (!isfound)
  58. {
  59. for (int i = size - 1; i >= 0; --i)
  60. {
  61. if (buf[i] == '\r')
  62. {
  63. ////如果是LE,还要确定\n的下一个是否是\0
  64. if ((code == UNICODE_LE) && ((i != size - 1) && (buf[i + 1] != '\0')))
  65. {
  66. continue;
  67. }
  68. ////如果是BE,还要确定\n的前一个是否是\0
  69. if ((code == UNICODE_BE) && ((i != 0) && (buf[i - 1] != '\0')))
  70. {
  71. continue;
  72. }
  73. isfound = true;
  74. break;
  75. }
  76. ++ret;
  77. }
  78. }
  79. if (isfound)
  80. {
  81. //注意好好想想,这里是--ret,而不是++ret。
  82. if (code == UNICODE_LE)
  83. {
  84. --ret;
  85. }
  86. //UNICODE_BE不需要处理
  87. return ret;
  88. }
  89. //说明是一个巨长的行,这种情况不是很好。直接读取了,不管是否进行了行截断
  90. return 0;
  91. }
  92. //从行首找后面的换行符号。返回的是需要前进的个数,即把前面掐掉一节,让返回在一行的行首位置
  93. int findLineStartPos(const char* buf, int size, CODE_ID code = UNKOWN)
  94. {
  95. int ret = 0;
  96. bool isfound = false;
  97. for (int i = 0; i < size; ++i)
  98. {
  99. ++ret;
  100. if (buf[i] == '\n')
  101. {
  102. ////如果是LE,还要确定\n的下一个是否是\0
  103. if ((code == UNICODE_LE) && ((i != size - 1) && (buf[i + 1] != '\0')))
  104. {
  105. continue;
  106. }
  107. ////如果是BE,还要确定\n的前一个是否是\0
  108. if ((code == UNICODE_BE) && ((i != 0) && (buf[i - 1] != '\0')))
  109. {
  110. continue;
  111. }
  112. isfound = true;
  113. break;
  114. }
  115. }
  116. //如果没有找到,怀疑是mac格式,按照\r结尾解析
  117. if (!isfound)
  118. {
  119. for (int i = size - 1; i >= 0; --i)
  120. {
  121. ++ret;
  122. if (buf[i] == '\r')
  123. {
  124. ////如果是LE,还要确定\n的下一个是否是\0
  125. if ((code == UNICODE_LE) && ((i != size - 1) && (buf[i + 1] != '\0')))
  126. {
  127. continue;
  128. }
  129. ////如果是BE,还要确定\n的前一个是否是\0
  130. if ((code == UNICODE_BE) && ((i != 0) && (buf[i - 1] != '\0')))
  131. {
  132. continue;
  133. }
  134. isfound = true;
  135. break;
  136. }
  137. }
  138. }
  139. if (isfound)
  140. {
  141. //注意好好想想,这里是++ret,而不是--ret。
  142. if (code == UNICODE_LE)
  143. {
  144. ++ret;
  145. }
  146. return ret;
  147. }
  148. //说明是一个巨长的行,这种情况不是很好。直接读取了,不管是否进行了行截断
  149. return 0;
  150. }
  151. //返回第一个空闲的id,m_newFileIdList必须有序,从小到大,从0开始
  152. //序号也从0开始,notepad++是从1开始
  153. int FileManager::getNextNewFileId()
  154. {
  155. if (m_newFileIdList.isEmpty())
  156. {
  157. return 0;
  158. }
  159. int index = 0;
  160. bool isFind = false;
  161. for (int i = 0; i < m_newFileIdList.size(); ++i)
  162. {
  163. if (m_newFileIdList.at(i).index > i)
  164. {
  165. index = i;
  166. isFind = true;
  167. break;
  168. }
  169. }
  170. if (!isFind)
  171. {
  172. index = m_newFileIdList.size();
  173. }
  174. return index;
  175. }
  176. //务必要保证不能重复id,所以newnode后,必须接着调用insertNewFileNode,避免重复了
  177. void FileManager::insertNewFileNode(NewFileIdMgr node)
  178. {
  179. m_newFileIdList.append(node);
  180. std::sort(m_newFileIdList.begin(), m_newFileIdList.end(), [](NewFileIdMgr& a, NewFileIdMgr& b) {
  181. return a.index < b.index;
  182. });
  183. }
  184. //删除newfile id的节点
  185. void FileManager::delNewFileNode(int fileIndex)
  186. {
  187. for (int i = 0; i < m_newFileIdList.size(); ++i)
  188. {
  189. if (m_newFileIdList.at(i).index == fileIndex)
  190. {
  191. m_newFileIdList.removeAt(i);
  192. break;
  193. }
  194. }
  195. }
  196. //这里是以文本方式加载文件。但是可能遇到的是二进制文件,里面会做判断
  197. //二进制时hexAsk是否询问,当用户指定打开格式时,不需要询问
  198. int FileManager::loadFileDataInText(ScintillaEditView* editView, QString filePath, CODE_ID& fileTextCode, RC_LINE_FORM& lineEnd,CCNotePad * callbackObj, bool hexAsk)
  199. {
  200. QFile file(filePath);
  201. //如果文件不存在,直接返回
  202. if (!file.exists())
  203. {
  204. return -1;
  205. }
  206. QFlags<QFileDevice::Permission> power = QFile::permissions(filePath);
  207. #if 0
  208. if (!power.testFlag(QFile::ReadOwner))
  209. {
  210. //文件不能读
  211. QMessageBox::warning(nullptr, tr("Error"), tr("Open File %1 failed Can not read auth").arg(filePath));
  212. return 1;
  213. }
  214. #endif
  215. //直接以只读的方式打开,至于能不能保存,是保存时需要考虑的问题。
  216. //只需要在保存的时候获取admin权限即可
  217. QIODevice::OpenMode mode;
  218. mode = QIODevice::ExistingOnly | QIODevice::ReadOnly;
  219. #if 0
  220. if (!power.testFlag(QFile::WriteUser))
  221. {
  222. //文件不能写
  223. mode = QIODevice::ExistingOnly | QIODevice::ReadOnly;
  224. }
  225. else
  226. {
  227. mode = QIODevice::ExistingOnly | QIODevice::ReadWrite;
  228. }
  229. #endif
  230. if (!file.open(mode))
  231. {
  232. qDebug() << file.error();
  233. #ifdef Q_OS_WIN
  234. //打开失败,这里一般是权限问题导致。如果是windows,在外面申请权限后继续处理
  235. if (QFileDevice::OpenError == file.error())
  236. {
  237. if (callbackObj != nullptr)
  238. {
  239. return callbackObj->runAsAdmin(filePath);
  240. }
  241. return 1;
  242. }
  243. #endif
  244. #ifdef Q_OS_UNIX
  245. QMessageBox::warning(nullptr, tr("Error"), tr("Open File %1 failed").arg(filePath));
  246. #endif
  247. return 2;
  248. }
  249. qint64 fileSize = file.size();
  250. //如果文件是空的。检查一下,有可能在临时文件损坏情况下出现,外面需要使用
  251. if (fileSize == 0)
  252. {
  253. m_lastErrorCode = ERROR_TYPE::OPEN_EMPTY_FILE;
  254. file.close();
  255. return 0;
  256. }
  257. qint64 bufferSizeRequested = fileSize + qMin((qint64)(1 << 20), (qint64)(fileSize / 6));
  258. // As a 32bit application, we cannot allocate 2 buffer of more than INT_MAX size (it takes the whole address space)
  259. if (bufferSizeRequested > INT_MAX)
  260. {
  261. QMessageBox::warning(nullptr, tr("Error"), tr("File is too big to be opened by Notepad--"));
  262. file.close();
  263. return 3;
  264. }
  265. QList<LineFileInfo> outputLineInfoVec;
  266. int maxLineSize = 0;
  267. int charsNums = 0;
  268. bool isHexFile = false;
  269. fileTextCode = CmpareMode::scanFileOutPut(fileTextCode,filePath, outputLineInfoVec, maxLineSize, charsNums, isHexFile);
  270. //如果文件是空的。检查一下,有可能在临时文件损坏情况下出现,外面需要使用
  271. if (charsNums == 0)
  272. {
  273. m_lastErrorCode = ERROR_TYPE::OPEN_EMPTY_FILE;
  274. file.close();
  275. return 0;
  276. }
  277. if (isHexFile && hexAsk)
  278. {
  279. //检测到文件很可能是二进制文件,询问用户,是否以二进制加载
  280. 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"));
  281. if (ret == 0)
  282. {
  283. //16进制打开
  284. file.close();
  285. return 4;
  286. }
  287. else if (ret == 1)
  288. {
  289. //继续以文本打开
  290. }
  291. else
  292. {
  293. //取消,不打开
  294. file.close();
  295. return 2;
  296. }
  297. }
  298. if (maxLineSize > 0)
  299. {
  300. //int textWidth = editView->execute(SCI_TEXTWIDTH, STYLE_DEFAULT, reinterpret_cast<sptr_t>("P"));
  301. editView->execute(SCI_SETSCROLLWIDTH, maxLineSize*10);
  302. }
  303. //以第一行的换行为文本的换行符
  304. lineEnd = UNKNOWN_LINE;
  305. if (!outputLineInfoVec.isEmpty())
  306. {
  307. lineEnd = static_cast<RC_LINE_FORM>(outputLineInfoVec.at(0).lineEndFormat);
  308. }
  309. if (lineEnd == UNKNOWN_LINE)
  310. {
  311. #ifdef _WIN32
  312. lineEnd = DOS_LINE;
  313. #else
  314. lineEnd = UNIX_LINE;
  315. #endif
  316. }
  317. QString text;
  318. text.reserve(charsNums + 1);
  319. for (QList<LineFileInfo>::iterator it = outputLineInfoVec.begin(); it != outputLineInfoVec.end(); ++it)
  320. {
  321. text.append(it->unicodeStr);
  322. }
  323. file.close();
  324. //优先根据文件后缀来确定其语法风格
  325. LexerInfo lxdata = CCNotePad::getLangLexerIdByFileExt(filePath);
  326. if (lxdata.lexerId != L_TXT)
  327. {
  328. QsciLexer* lexer = editView->createLexer(lxdata.lexerId, lxdata.tagName);
  329. editView->setLexer(lexer);
  330. }
  331. else
  332. {
  333. //利用前面5行,进行一个编程语言的判断
  334. QString headContens;
  335. for (int i = 0; (i < outputLineInfoVec.size() && i < 5); ++i)
  336. {
  337. headContens.append(outputLineInfoVec.at(i).unicodeStr);
  338. }
  339. std::string headstr = headContens.toStdString();
  340. LangType _language = detectLanguageFromTextBegining((const unsigned char *)headstr.data(), headstr.length());
  341. if (_language >= 0 && _language < L_EXTERNAL)
  342. {
  343. QsciLexer* lexer = editView->createLexer(_language);
  344. editView->setLexer(lexer);
  345. }
  346. }
  347. //如果检测到时16进制文件,但是强行以二进制打开,则有限走setUtf8Text。
  348. if (!isHexFile)
  349. {
  350. editView->setText(text);
  351. }
  352. else
  353. {
  354. //这种情况,为了不编辑二进制模式,是可能只读的。
  355. if (1 == editView->setUtf8Text(text))
  356. {
  357. return 5;//只读模式
  358. }
  359. }
  360. return 0;
  361. }
  362. //加载文件,只为查找使用
  363. int FileManager::loadFileForSearch(ScintillaEditView* editView, QString filePath)
  364. {
  365. QFile file(filePath);
  366. QFlags<QFileDevice::Permission> power = QFile::permissions(filePath);
  367. if (!power.testFlag(QFile::ReadOwner))
  368. {
  369. //文件不能读
  370. return 1;
  371. }
  372. QIODevice::OpenMode mode;
  373. if (!power.testFlag(QFile::WriteOwner))
  374. {
  375. //文件不能写
  376. mode = QIODevice::ExistingOnly | QIODevice::ReadOnly;
  377. }
  378. else
  379. {
  380. mode = QIODevice::ExistingOnly | QIODevice::ReadWrite;
  381. }
  382. if (!file.open(mode))
  383. {
  384. qDebug() << file.error();
  385. return 2;
  386. }
  387. qint64 fileSize = file.size();
  388. qint64 bufferSizeRequested = fileSize + qMin((qint64)(1 << 20), (qint64)(fileSize / 6));
  389. // As a 32bit application, we cannot allocate 2 buffer of more than INT_MAX size (it takes the whole address space)
  390. if (bufferSizeRequested > INT_MAX)
  391. {
  392. file.close();
  393. return 3;
  394. }
  395. QList<LineFileInfo> outputLineInfoVec;
  396. int maxLineSize = 0;
  397. int charsNums = 0;
  398. bool isHexFile = false;
  399. CODE_ID fileTextCode = CODE_ID::UNKOWN;
  400. CmpareMode::scanFileOutPut(fileTextCode, filePath, outputLineInfoVec, maxLineSize, charsNums, isHexFile);
  401. if (isHexFile)
  402. {
  403. qDebug() << filePath;
  404. file.close();
  405. return 4;
  406. }
  407. if (maxLineSize > 0)
  408. {
  409. editView->execute(SCI_SETSCROLLWIDTH, maxLineSize * 10);
  410. }
  411. QString text;
  412. text.reserve(charsNums + 1);
  413. for (QList<LineFileInfo>::iterator it = outputLineInfoVec.begin(); it != outputLineInfoVec.end(); ++it)
  414. {
  415. text.append(it->unicodeStr);
  416. }
  417. file.close();
  418. editView->setText(text);
  419. return 0;
  420. }
  421. const int ONE_PAGE_BYTES = 4096;
  422. //加载下一页或者上一页。(二进制模式)
  423. int FileManager::loadFilePreNextPage(int dir, QString& filePath, HexFileMgr* & hexFileOut)
  424. {
  425. if (m_hexFileMgr.contains(filePath))
  426. {
  427. hexFileOut = m_hexFileMgr.value(filePath);
  428. //小于LITTLE_FILE_MAX的已经一次性全部在内存,没有上下页可以翻到
  429. if (hexFileOut->onetimeRead)
  430. {
  431. return 1;
  432. }
  433. qint64 pos = hexFileOut->fileOffset;
  434. if (dir == 1 && (pos >= 0))
  435. {
  436. //上一页
  437. pos = pos - hexFileOut->contentRealSize - ONE_PAGE_BYTES;
  438. if (pos < 0)
  439. {
  440. pos = 0;
  441. }
  442. }
  443. else if(dir == 2 && (pos < hexFileOut->fileSize))
  444. {
  445. }
  446. else
  447. {
  448. return 1;//没有上下页,已经是最后一页或最前一页
  449. }
  450. char* buf = new char[ONE_PAGE_BYTES+1];
  451. hexFileOut->file->seek(pos);
  452. qint64 ret = hexFileOut->file->read(buf, ONE_PAGE_BYTES);
  453. if (ret <= 0)
  454. {
  455. return -1;
  456. }
  457. else
  458. {
  459. //读取成功
  460. hexFileOut->fileOffset = hexFileOut->file->pos();
  461. if (hexFileOut->contentBuf != nullptr)
  462. {
  463. delete[]hexFileOut->contentBuf;
  464. }
  465. hexFileOut->contentBuf = buf;
  466. hexFileOut->contentRealSize = ret;
  467. }
  468. return 0;
  469. }
  470. return -1;
  471. }
  472. const int ONE_PAGE_TEXT_SIZE = 1000 * 1024;
  473. //加载下一页或者上一页。(文本模式)
  474. //返回值:0表示成功
  475. int FileManager::loadFilePreNextPage(int dir, QString& filePath, TextFileMgr* & textFileOut)
  476. {
  477. if (m_bigTxtFileMgr.contains(filePath))
  478. {
  479. textFileOut = m_bigTxtFileMgr.value(filePath);
  480. qint64 pos = textFileOut->fileOffset;
  481. int canReadSize = 0;
  482. if (dir == 1 && (pos >= 0))
  483. {
  484. //读取上一页
  485. pos = pos - textFileOut->contentRealSize - ONE_PAGE_TEXT_SIZE;
  486. if (pos < 0)
  487. {
  488. //前面的内容不足以ONE_PAGE_TEXT_SIZE字节
  489. canReadSize = textFileOut->fileOffset - textFileOut->contentRealSize;
  490. if (canReadSize <= 0)
  491. {
  492. return 1;
  493. }
  494. pos = 0;
  495. }
  496. else
  497. {
  498. canReadSize = ONE_PAGE_TEXT_SIZE;
  499. }
  500. }
  501. else if (dir == 2 && (pos < textFileOut->fileSize))
  502. {
  503. canReadSize = ONE_PAGE_TEXT_SIZE;
  504. }
  505. else
  506. {
  507. return 1;
  508. }
  509. char* buf = new char[canReadSize + 1];
  510. buf[canReadSize] = '\0';
  511. textFileOut->file->seek(pos);
  512. qint64 ret = textFileOut->file->read(buf, canReadSize);
  513. if (ret <= 0)
  514. {
  515. return -1;
  516. }
  517. else
  518. {
  519. //读取成功
  520. //如果是往后读取
  521. if (dir == 2)
  522. {
  523. //读取了1M的内容,从内容尾部往前查找,找到第一个换行符号。如果没有怎么办?说明是一个巨长的行,不妙
  524. //如果是巨长的行,一行超过ONE_PAGE_TEXT_SIZE(1M),则可能存在单个字符截断的可能。
  525. buf[ret] = '\0';
  526. int preLineEndPos = 0;
  527. if (textFileOut->file->pos() < textFileOut->fileSize)//反之已经到尾部了,不需要往前找行首了
  528. {
  529. preLineEndPos = findLineEndPos(buf, ret, (CODE_ID)textFileOut->loadWithCode);
  530. if (preLineEndPos > 0)
  531. {
  532. //给后面的字符填\0,让字符串正常结尾\0
  533. buf[ret - preLineEndPos] = '\0';
  534. }
  535. }
  536. textFileOut->fileOffset = textFileOut->file->pos() -preLineEndPos;
  537. if (preLineEndPos > 0)
  538. {
  539. //文件seek到下一行的首位置。
  540. textFileOut->file->seek(textFileOut->fileOffset);
  541. }
  542. if (textFileOut->contentBuf != nullptr)
  543. {
  544. delete[]textFileOut->contentBuf;
  545. }
  546. textFileOut->contentBuf = buf;
  547. textFileOut->contentRealSize = ret - preLineEndPos;
  548. }
  549. else if (dir == 1)
  550. {
  551. //如果是往前读取
  552. //读取了1M的内容,从内容前面往后查找,找到第一个换行符号。如果没有怎么办?说明是一个巨长的行,不妙
  553. buf[ret] = '\0';
  554. int preLineStartPos = 0;
  555. if (textFileOut->file->pos() > canReadSize)//==canReadSize说明已经在文件最前面了。不在最前面,需要
  556. {
  557. preLineStartPos = findLineStartPos(buf, ret, (CODE_ID)textFileOut->loadWithCode);
  558. if (preLineStartPos > 0)
  559. {
  560. //把\n前面的内容去掉,通过内存move的方式。
  561. memmove(buf, buf+preLineStartPos,ret - preLineStartPos);
  562. buf[ret - preLineStartPos] = '\0';
  563. }
  564. }
  565. textFileOut->fileOffset = textFileOut->file->pos();
  566. if (textFileOut->contentBuf != nullptr)
  567. {
  568. delete[]textFileOut->contentBuf;
  569. }
  570. textFileOut->contentBuf = buf;
  571. textFileOut->contentRealSize = ret - preLineStartPos;
  572. }
  573. }
  574. return 0;
  575. }
  576. return -1;
  577. }
  578. //从指定地址开始加载文件
  579. int FileManager::loadFileFromAddr(QString filePath, qint64 addr, HexFileMgr* & hexFileOut)
  580. {
  581. if (m_hexFileMgr.contains(filePath))
  582. {
  583. hexFileOut = m_hexFileMgr.value(filePath);
  584. //超过文件大小
  585. if (addr < 0 || addr >= hexFileOut->fileSize)
  586. {
  587. return -2;
  588. }
  589. //4K对齐
  590. addr &= 0xfffffffffff0;
  591. char* buf = new char[ONE_PAGE_BYTES + 1];
  592. hexFileOut->file->seek(addr);
  593. qint64 ret = hexFileOut->file->read(buf, ONE_PAGE_BYTES);
  594. if (ret <= 0)
  595. {
  596. return -1;
  597. }
  598. else
  599. {
  600. //读取成功
  601. hexFileOut->fileOffset = hexFileOut->file->pos();
  602. if (hexFileOut->contentBuf != nullptr)
  603. {
  604. delete[]hexFileOut->contentBuf;
  605. }
  606. hexFileOut->contentBuf = buf;
  607. hexFileOut->contentRealSize = ret;
  608. }
  609. return 0;
  610. }
  611. return -1;
  612. }
  613. //从指定地址开始加载文本文件
  614. int FileManager::loadFileFromAddr(QString filePath, qint64 addr, TextFileMgr* & textFileOut)
  615. {
  616. if (m_bigTxtFileMgr.contains(filePath))
  617. {
  618. textFileOut = m_bigTxtFileMgr.value(filePath);
  619. //超过文件大小
  620. if (addr < 0 || addr >= textFileOut->fileSize)
  621. {
  622. return -2;
  623. }
  624. char* buf = new char[ONE_PAGE_TEXT_SIZE + 1];
  625. buf[ONE_PAGE_TEXT_SIZE] = '\0';
  626. textFileOut->file->seek(addr);
  627. qint64 ret = textFileOut->file->read(buf, ONE_PAGE_TEXT_SIZE);
  628. if (ret <= 0)//-1是出错。0也是没有读到
  629. {
  630. return -1;
  631. }
  632. else
  633. {
  634. int preLineEndPos = 0;
  635. buf[ret] = '\0';
  636. if (textFileOut->file->pos() < textFileOut->fileSize)//反之已经到尾部了,不需要往前找行了
  637. {
  638. preLineEndPos = findLineEndPos(buf, ret, (CODE_ID)textFileOut->loadWithCode);
  639. if (preLineEndPos > 0)
  640. {
  641. //给后面的字符填\0,让字符串正常结尾\0
  642. buf[ret - preLineEndPos] = '\0';
  643. }
  644. }
  645. //如果本来就在开头开始,则不需要计算findLineStartPos
  646. int preLineStartPos = 0;
  647. if (addr == 0)
  648. {
  649. }
  650. else
  651. {
  652. preLineStartPos = findLineStartPos(buf, ret, (CODE_ID)textFileOut->loadWithCode);
  653. if (preLineStartPos > 0 && preLineStartPos < ret) //preLineStartPos如果大于ret,则全部都被跳过了,不会显示,是个特例
  654. {
  655. memmove(buf, buf + preLineStartPos, ret - preLineStartPos);
  656. buf[ret - preLineStartPos] = '\0';
  657. }
  658. else
  659. {
  660. //如果没做调整,则后续不需要偏移,这里必须preLineStartPos赋0值
  661. preLineStartPos = 0;
  662. }
  663. }
  664. //只需要文件调到上一行的行位即可。
  665. textFileOut->fileOffset = textFileOut->file->pos() - preLineEndPos;
  666. if (preLineEndPos > 0)
  667. {
  668. //文件seek到下一行的首位置。
  669. textFileOut->file->seek(textFileOut->fileOffset);
  670. }
  671. if (textFileOut->contentBuf != nullptr)
  672. {
  673. delete[]textFileOut->contentBuf;
  674. }
  675. textFileOut->contentBuf = buf;
  676. textFileOut->contentRealSize = ret - preLineEndPos - preLineStartPos;
  677. }
  678. return 0;
  679. }
  680. return -1;
  681. }
  682. //加载二进制文件。从curPos开始,每行16个byte,每次读取64行,一共1024个byte
  683. bool FileManager::loadFileData(QString filePath, HexFileMgr* & hexFileOut)
  684. {
  685. QFile *file = new QFile(filePath);
  686. if (!file->open(QIODevice::ReadOnly | QIODevice::ExistingOnly))
  687. {
  688. return false;
  689. }
  690. int readBytes = 0;
  691. if (file->size() <= LITTLE_FILE_MAX)
  692. {
  693. readBytes = LITTLE_FILE_MAX;
  694. }
  695. else
  696. {
  697. //对于大于10K的文件,每次只读4K
  698. readBytes = ONE_PAGE_BYTES;
  699. }
  700. char* buf = new char[readBytes];
  701. qint64 ret = file->read(buf, readBytes);
  702. if (ret == -1)
  703. {
  704. //错误
  705. file->close();
  706. delete file;
  707. return false;
  708. }
  709. else
  710. {
  711. HexFileMgr* hexFile = nullptr;
  712. if (!m_hexFileMgr.contains(filePath))
  713. {
  714. hexFile = new HexFileMgr();
  715. hexFile->filePath = filePath;
  716. hexFile->file = file;
  717. hexFile->fileOffset = file->pos();
  718. hexFile->fileSize = file->size();
  719. hexFile->contentBuf = buf;
  720. hexFile->contentRealSize = ret;
  721. hexFile->onetimeRead = (file->size() <= LITTLE_FILE_MAX);
  722. m_hexFileMgr.insert(filePath, hexFile);
  723. }
  724. else
  725. {
  726. //理论上这里永远不走
  727. hexFile = m_hexFileMgr.value(filePath);
  728. hexFile->fileOffset = file->pos();
  729. hexFile->contentBuf = buf;
  730. hexFile->contentRealSize = ret;
  731. hexFile->onetimeRead = (file->size() <= LITTLE_FILE_MAX);
  732. }
  733. hexFileOut = hexFile;
  734. return true;
  735. }
  736. return false;
  737. }
  738. //加载大文本文件。从0开始读取ONE_PAGE_TEXT_SIZE 500K的内容
  739. bool FileManager::loadFileData(QString filePath, TextFileMgr* & textFileOut, RC_LINE_FORM & lineEnd)
  740. {
  741. QFile *file = new QFile(filePath);
  742. if (!file->open(QIODevice::ReadOnly | QIODevice::ExistingOnly))
  743. {
  744. return false;
  745. }
  746. int readBytes = ONE_PAGE_TEXT_SIZE;
  747. char* buf = new char[ONE_PAGE_TEXT_SIZE+1];
  748. buf[ONE_PAGE_TEXT_SIZE] = '\0';
  749. qint64 ret = file->read(buf, readBytes);
  750. if (ret <= 0)
  751. {
  752. //错误
  753. file->close();
  754. delete file;
  755. return false;
  756. }
  757. else
  758. {
  759. //读取了1M的内容,从尾部往找,找到第一个换行符号。如果没有怎么办?说明是一个巨长的行,不妙
  760. buf[ret] = '\0';
  761. CODE_ID code = CmpareMode::getTextFileEncodeType((uchar*)buf, ret, filePath, true);
  762. int preLineEndPos = findLineEndPos(buf,ret, code);
  763. if (preLineEndPos > 0)
  764. {
  765. //给后面的字符填\0,让字符串正常结尾\0
  766. buf[ret - preLineEndPos] = '\0';
  767. if (ret - preLineEndPos >= 2)
  768. {
  769. if (buf[ret - preLineEndPos - 1] == '\n' && buf[ret - preLineEndPos - 2] == '\r')
  770. {
  771. lineEnd = DOS_LINE;
  772. }
  773. else if (buf[ret - preLineEndPos - 1] == '\n')
  774. {
  775. lineEnd = UNIX_LINE;
  776. }
  777. else if (buf[ret - preLineEndPos - 1] == '\r')
  778. {
  779. lineEnd = MAC_LINE;
  780. }
  781. }
  782. }
  783. TextFileMgr* txtFile = nullptr;
  784. if (!m_bigTxtFileMgr.contains(filePath))
  785. {
  786. txtFile = new TextFileMgr();
  787. txtFile->loadWithCode = code;
  788. txtFile->filePath = filePath;
  789. txtFile->file = file;
  790. txtFile->fileOffset = file->pos() - preLineEndPos;
  791. if (preLineEndPos > 0)
  792. {
  793. //文件seek到下一行的首位置。下次读的时候,头部肯定是一行的行首啦
  794. file->seek(txtFile->fileOffset);
  795. }
  796. txtFile->fileSize = file->size();
  797. txtFile->contentBuf = buf;
  798. txtFile->contentRealSize = ret - preLineEndPos;
  799. m_bigTxtFileMgr.insert(filePath, txtFile);
  800. }
  801. else
  802. {
  803. //理论上这里永远不走
  804. assert(false);
  805. txtFile = m_bigTxtFileMgr.value(filePath);
  806. txtFile->fileOffset = file->pos();
  807. txtFile->contentBuf = buf;
  808. txtFile->contentRealSize = ret;
  809. }
  810. textFileOut = txtFile;
  811. return true;
  812. }
  813. return false;
  814. }
  815. //返回行的数量
  816. int getLineNumInBuf(char* buf, int size, CODE_ID code = UNKOWN)
  817. {
  818. int lineNums = 0;
  819. for (int i = 0; i < size; ++i)
  820. {
  821. if (buf[i] == '\n')
  822. {
  823. ////如果是LE,还要确定\n的下一个是否是\0
  824. if ((code == UNICODE_LE) && ((i != size - 1) && (buf[i + 1] != '\0')))
  825. {
  826. continue;
  827. }
  828. //如果是BE,简单\0\n是否连续存在,不能单纯检查\n,还有确定\n的前一个是不是\0
  829. if ((code == UNICODE_BE) && ((i != 0) && (buf[i - 1] != '\0')))
  830. {
  831. continue;
  832. }
  833. ++lineNums;
  834. }
  835. }
  836. //如果没有找到,怀疑是mac格式,按照\r结尾解析
  837. if (lineNums == 0)
  838. {
  839. for (int i = 0; i < size; ++i)
  840. {
  841. if (buf[i] == '\r')
  842. {
  843. ////如果是LE,还要确定\n的前面一个是否是\0
  844. if ((code == UNICODE_LE) && ((i != size - 1) && (buf[i + 1] != '\0')))
  845. {
  846. continue;
  847. }
  848. //如果是BE,简单\0\n是否连续存在,不能单纯检查\n,还有确定\n的前一个是不是\0
  849. if ((code == UNICODE_BE) && ((i != 0) && (buf[i - 1] != '\0')))
  850. {
  851. continue;
  852. }
  853. ++lineNums;
  854. }
  855. }
  856. }
  857. return lineNums;
  858. }
  859. //创建大文件编辑模式的索引文件。0 成功,-1取消
  860. int FileManager::createBlockIndex(BigTextEditFileMgr* txtFile)
  861. {
  862. //每次filePtr 4M的速度进行建块
  863. qint64 fileSize = txtFile->file->size();
  864. qint64 curOffset = 0;
  865. uchar* curPtr = txtFile->filePtr;
  866. //检测是否为unicode_le编码,要特殊对待。
  867. //bool isUnLeCode = CmpareMode::isUnicodeLeBomFile(curPtr, 2);
  868. CODE_ID code = CmpareMode::getTextFileEncodeType(curPtr, fileSize, txtFile->filePath, true);
  869. txtFile->loadWithCode = code;
  870. const int blockBytes = BigTextEditFileMgr::BLOCK_SIZE * 1024 * 1024;
  871. int lineEndPos = 0;
  872. int steps = fileSize / blockBytes;
  873. txtFile->blocks.reserve(steps + 10);
  874. ProgressWin* loadFileProcessWin = nullptr;
  875. if (steps > 200)
  876. {
  877. loadFileProcessWin = new ProgressWin(nullptr);
  878. loadFileProcessWin->setWindowModality(Qt::ApplicationModal);
  879. loadFileProcessWin->info(tr("load bit text file tree in progress\nfile size %1, please wait ...").arg(tranFileSize(fileSize)));
  880. loadFileProcessWin->setTotalSteps(steps);
  881. loadFileProcessWin->show();
  882. }
  883. quint32 lineNumStart = 0;
  884. quint32 lineNum = 0;
  885. while ((curOffset + blockBytes) < fileSize)
  886. {
  887. BlockIndex bi;
  888. bi.fileOffset = curOffset;
  889. curOffset += blockBytes;
  890. lineEndPos = findLineEndPos((char*)curPtr+ bi.fileOffset, blockBytes, code);
  891. bi.fileSize = blockBytes - lineEndPos;
  892. lineNum = getLineNumInBuf((char*)curPtr + bi.fileOffset, bi.fileSize, code);
  893. curOffset -= lineEndPos;
  894. bi.lineNum = lineNum;
  895. bi.lineNumStart = lineNumStart;
  896. lineNumStart += lineNum;
  897. txtFile->blocks.append(bi);
  898. if (loadFileProcessWin != nullptr)
  899. {
  900. if (loadFileProcessWin->isCancel())
  901. {
  902. delete loadFileProcessWin;
  903. txtFile->blocks.clear();
  904. return -1;
  905. }
  906. loadFileProcessWin->moveStep(true);
  907. }
  908. }
  909. //最后一块
  910. int lastBlockBytes = fileSize - curOffset;
  911. BlockIndex bi;
  912. bi.fileOffset = curOffset;
  913. curOffset += lastBlockBytes;
  914. bi.fileSize = lastBlockBytes;
  915. lineNum = getLineNumInBuf((char*)curPtr + bi.fileOffset, bi.fileSize);
  916. bi.lineNum = lineNum;
  917. bi.lineNumStart = lineNumStart;
  918. txtFile->blocks.append(bi);
  919. if (loadFileProcessWin != nullptr)
  920. {
  921. delete loadFileProcessWin;
  922. }
  923. return 0;
  924. }
  925. //加载大文件,以索引的方式打开大文件
  926. bool FileManager::loadFileDataWithIndex(QString filePath, BigTextEditFileMgr*& textFileOut)
  927. {
  928. QFile* file = new QFile(filePath);
  929. file->open(QIODevice::ReadOnly);
  930. uchar* filePtr = file->map(0, file->size());
  931. BigTextEditFileMgr* txtFile = nullptr;
  932. if (!m_bigTxtEditFileMgr.contains(filePath))
  933. {
  934. txtFile = new BigTextEditFileMgr();
  935. txtFile->filePath = filePath;
  936. txtFile->file = file;
  937. txtFile->filePtr = filePtr;
  938. textFileOut = txtFile;
  939. if (-1 == createBlockIndex(txtFile))
  940. {
  941. //取消。
  942. delete txtFile;
  943. txtFile = nullptr;
  944. return false;
  945. }
  946. m_bigTxtEditFileMgr.insert(filePath, txtFile);
  947. }
  948. else
  949. {
  950. //理论上这里永远不走
  951. assert(false);
  952. }
  953. return true;
  954. }
  955. BigTextEditFileMgr* FileManager::getBigFileEditMgr(QString filepath)
  956. {
  957. if (m_bigTxtEditFileMgr.contains(filepath))
  958. {
  959. return m_bigTxtEditFileMgr.value(filepath);
  960. }
  961. return nullptr;
  962. }
  963. TextFileMgr* FileManager::getSuperBigFileMgr(QString filepath)
  964. {
  965. if (m_bigTxtFileMgr.contains(filepath))
  966. {
  967. return m_bigTxtFileMgr.value(filepath);
  968. }
  969. return nullptr;
  970. }
  971. int FileManager::getBigFileBlockId(QString filepath, quint32 lineNum)
  972. {
  973. BigTextEditFileMgr* v = m_bigTxtEditFileMgr.value(filepath);
  974. for (int i = 0, s = v->blocks.size(); i < s; ++i)
  975. {
  976. const BlockIndex& k = v->blocks.at(i);
  977. if (lineNum >= k.lineNumStart && lineNum < (k.lineNumStart + k.lineNum))
  978. {
  979. return i;
  980. }
  981. }
  982. return -1;
  983. }
  984. HexFileMgr * FileManager::getHexFileHand(QString filepath)
  985. {
  986. if (m_hexFileMgr.contains(filepath))
  987. {
  988. return m_hexFileMgr.value(filepath);
  989. }
  990. return nullptr;
  991. }
  992. void FileManager::closeHexFileHand(QString filepath)
  993. {
  994. if (m_hexFileMgr.contains(filepath))
  995. {
  996. HexFileMgr* v = m_hexFileMgr.value(filepath);
  997. v->destory();
  998. delete v;
  999. m_hexFileMgr.remove(filepath);
  1000. }
  1001. }
  1002. void FileManager::closeSuperBigTextFileHand(QString filepath)
  1003. {
  1004. if (m_bigTxtFileMgr.contains(filepath))
  1005. {
  1006. TextFileMgr* v = m_bigTxtFileMgr.value(filepath);
  1007. v->destory();
  1008. delete v;
  1009. m_bigTxtFileMgr.remove(filepath);
  1010. }
  1011. }
  1012. void FileManager::closeBigTextRoFileHand(QString filepath)
  1013. {
  1014. if (m_bigTxtEditFileMgr.contains(filepath))
  1015. {
  1016. BigTextEditFileMgr* v = m_bigTxtEditFileMgr.value(filepath);
  1017. v->destory();
  1018. delete v;
  1019. m_bigTxtEditFileMgr.remove(filepath);
  1020. }
  1021. }
  1022. //检查文件的编程语言
  1023. LangType FileManager::detectLanguageFromTextBegining(const unsigned char *data, size_t dataLen)
  1024. {
  1025. struct FirstLineLanguages
  1026. {
  1027. std::string pattern;
  1028. LangType lang;
  1029. };
  1030. // Is the buffer at least the size of a BOM?
  1031. if (dataLen <= 3)
  1032. return L_TXT;
  1033. // Eliminate BOM if present
  1034. size_t i = 0;
  1035. if ((data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF) || // UTF8 BOM
  1036. (data[0] == 0xFE && data[1] == 0xFF && data[2] == 0x00) || // UTF16 BE BOM
  1037. (data[0] == 0xFF && data[1] == 0xFE && data[2] == 0x00)) // UTF16 LE BOM
  1038. i += 3;
  1039. // Skip any space-like char
  1040. for (; i < dataLen; ++i)
  1041. {
  1042. if (data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r')
  1043. break;
  1044. }
  1045. // Create the buffer to need to test
  1046. const size_t longestLength = 40; // shebangs can be large
  1047. std::string buf2Test = std::string((const char *)data + i, longestLength);
  1048. // Is there a \r or \n in the buffer? If so, truncate it
  1049. auto cr = buf2Test.find("\r");
  1050. auto nl = buf2Test.find("\n");
  1051. auto crnl = qMin(cr, nl);
  1052. if (crnl != std::string::npos && crnl < longestLength)
  1053. buf2Test = std::string((const char *)data + i, crnl);
  1054. // First test for a Unix-like Shebang
  1055. // See https://en.wikipedia.org/wiki/Shebang_%28Unix%29 for more details about Shebang
  1056. std::string shebang = "#!";
  1057. size_t foundPos = buf2Test.find(shebang);
  1058. if (foundPos == 0)
  1059. {
  1060. // Make a list of the most commonly used languages
  1061. const size_t NB_SHEBANG_LANGUAGES = 7;
  1062. FirstLineLanguages ShebangLangs[NB_SHEBANG_LANGUAGES] = {
  1063. { "sh", L_BASH },
  1064. { "python", L_PYTHON },
  1065. { "perl", L_PERL },
  1066. { "php", L_PHP },
  1067. { "ruby", L_RUBY },
  1068. { "node", L_JAVASCRIPT },
  1069. { "Makefile", L_MAKEFILE}
  1070. };
  1071. // Go through the list of languages
  1072. for (i = 0; i < NB_SHEBANG_LANGUAGES; ++i)
  1073. {
  1074. if (buf2Test.find(ShebangLangs[i].pattern) != std::string::npos)
  1075. {
  1076. return ShebangLangs[i].lang;
  1077. }
  1078. }
  1079. // Unrecognized shebang (there is always room for improvement ;-)
  1080. return L_TXT;
  1081. }
  1082. // Are there any other patterns we know off?
  1083. const size_t NB_FIRST_LINE_LANGUAGES = 5;
  1084. FirstLineLanguages languages[NB_FIRST_LINE_LANGUAGES] = {
  1085. { "<?xml", L_XML },
  1086. { "<?php", L_PHP },
  1087. { "<html", L_HTML },
  1088. { "<!DOCTYPE html", L_HTML },
  1089. { "<?", L_PHP } // MUST be after "<?php" and "<?xml" to get the result as accurate as possible
  1090. };
  1091. for (i = 0; i < NB_FIRST_LINE_LANGUAGES; ++i)
  1092. {
  1093. foundPos = buf2Test.find(languages[i].pattern);
  1094. if (foundPos == 0)
  1095. {
  1096. return languages[i].lang;
  1097. }
  1098. }
  1099. // Unrecognized first line, we assume it is a text file for now
  1100. return L_UNKNOWN;
  1101. }