bool FileManager::reloadBuffer(BufferID id) { Buffer * buf = getBufferByID(id); Document doc = buf->getDocument(); Utf8_16_Read UnicodeConvertor; buf->_canNotify = false; // Disable notify during file load, we don't want dirty to be triggered int encoding = buf->getEncoding(); formatType format; bool res = loadFileData(doc, buf->getFullPathName(), &UnicodeConvertor, buf->getLangType(), encoding, &format); buf->_canNotify = true; if (res) { if (encoding == -1) { if (UnicodeConvertor.getNewBuf()) { int format = getEOLFormatForm(UnicodeConvertor.getNewBuf()); buf->setFormat(format == -1?WIN_FORMAT:(formatType)format); } else { buf->setFormat(WIN_FORMAT); } buf->setUnicodeMode(UnicodeConvertor.getEncoding()); } else { buf->setEncoding(encoding); buf->setFormat(format); buf->setUnicodeMode(uniCookie); } } return res; }
bool FileManager::reloadBuffer(BufferID id) { Buffer* buf = getBufferByID(id); Document doc = buf->getDocument(); Utf8_16_Read UnicodeConvertor; buf->_canNotify = false; //disable notify during file load, we dont want dirty to be triggered int encoding = buf->getEncoding(); char data[blockSize + 8]; // +8 for incomplete multibyte char FormatType bkformat; LangType lang = buf->getLangType(); bool res = loadFileData(doc, buf->getFullPathName(), data, &UnicodeConvertor, lang, encoding, &bkformat); buf->_canNotify = true; if (res) { if (encoding == -1) { if (nullptr != UnicodeConvertor.getNewBuf()) { FormatType format = getEOLFormatForm(UnicodeConvertor.getNewBuf(), UnicodeConvertor.getNewSize()); buf->setFormat(format); } else buf->setFormat(FormatType::osdefault); buf->setUnicodeMode(UnicodeConvertor.getEncoding()); } else { buf->setEncoding(encoding); buf->setFormat(bkformat); buf->setUnicodeMode(uniCookie); } } return res; }
// backupFileName is sentinel of backup mode: if it's not NULL, then we use it (load it). Otherwise we use filename BufferID FileManager::loadFile(const TCHAR * filename, Document doc, int encoding, const TCHAR *backupFileName, time_t fileNameTimestamp) { bool ownDoc = false; if (doc == NULL) { doc = (Document)_pscratchTilla->execute(SCI_CREATEDOCUMENT); ownDoc = true; } TCHAR fullpath[MAX_PATH]; ::GetFullPathName(filename, MAX_PATH, fullpath, NULL); ::GetLongPathName(fullpath, fullpath, MAX_PATH); bool isSnapshotMode = backupFileName != NULL && PathFileExists(backupFileName); if (isSnapshotMode && !PathFileExists(fullpath)) // if backup mode and fullpath doesn't exist, we guess is UNTITLED { lstrcpy(fullpath, filename); // we restore fullpath with filename, in our case is "new #" } Utf8_16_Read UnicodeConvertor; //declare here so we can get information after loading is done char data[blockSize + 8]; // +8 for incomplete multibyte char FormatType bkformat = FormatType::unknown; LangType detectedLang = L_TEXT; bool res = loadFileData(doc, backupFileName ? backupFileName : fullpath, data, &UnicodeConvertor, detectedLang, encoding, &bkformat); if (res) { Buffer* newBuf = new Buffer(this, _nextBufferID, doc, DOC_REGULAR, fullpath); BufferID id = (BufferID) newBuf; newBuf->_id = id; if (backupFileName != NULL) { newBuf->_backupFileName = backupFileName; if (!PathFileExists(fullpath)) newBuf->_currentStatus = DOC_UNNAMED; } if (fileNameTimestamp != 0) newBuf->_timeStamp = fileNameTimestamp; _buffers.push_back(newBuf); ++_nrBufs; Buffer* buf = _buffers.at(_nrBufs - 1); // restore the encoding (ANSI based) while opening the existing file NppParameters *pNppParamInst = NppParameters::getInstance(); const NewDocDefaultSettings & ndds = (pNppParamInst->getNppGUI()).getNewDocDefaultSettings(); buf->setUnicodeMode(ndds._unicodeMode); buf->setEncoding(-1); // if a language has been detected, and the detected value is different from the file extension, // we use the detected value if (detectedLang != L_TEXT && detectedLang != buf->getLangType()) buf->setLangType(detectedLang); if (encoding == -1) { // 3 formats : WIN_FORMAT, UNIX_FORMAT and MAC_FORMAT if (nullptr != UnicodeConvertor.getNewBuf()) { FormatType format = getEOLFormatForm(UnicodeConvertor.getNewBuf(), UnicodeConvertor.getNewSize()); buf->setFormat(format); } else buf->setFormat(FormatType::osdefault); UniMode um = UnicodeConvertor.getEncoding(); if (um == uni7Bit) um = (ndds._openAnsiAsUtf8) ? uniCookie : uni8Bit; buf->setUnicodeMode(um); } else // encoding != -1 { // Test if encoding is set to UTF8 w/o BOM (usually for utf8 indicator of xml or html) buf->setEncoding((encoding == SC_CP_UTF8)?-1:encoding); buf->setUnicodeMode(uniCookie); buf->setFormat(bkformat); } //determine buffer properties ++_nextBufferID; return id; } else //failed loading, release document { if (ownDoc) _pscratchTilla->execute(SCI_RELEASEDOCUMENT, 0, doc); //Failure, so release document return BUFFER_INVALID; } }
inline bool FileManager::loadFileData(Document doc, const TCHAR * filename, char* data, Utf8_16_Read * UnicodeConvertor, LangType & language, int & encoding, FormatType* pFormat) { FILE *fp = generic_fopen(filename, TEXT("rb")); if (!fp) return false; //Get file size _fseeki64 (fp , 0 , SEEK_END); unsigned __int64 fileSize =_ftelli64(fp); rewind(fp); // size/6 is the normal room Scintilla keeps for editing, but here we limit it to 1MiB when loading (maybe we want to load big files without editing them too much) unsigned __int64 bufferSizeRequested = fileSize + min(1<<20,fileSize/6); // As a 32bit application, we cannot allocate 2 buffer of more than INT_MAX size (it takes the whole address space) if(bufferSizeRequested > INT_MAX) { ::MessageBox(NULL, TEXT("File is too big to be opened by Notepad++"), TEXT("File open problem"), MB_OK|MB_APPLMODAL); /* _nativeLangSpeaker.messageBox("NbFileToOpenImportantWarning", _pPublicInterface->getHSelf(), TEXT("File is too big to be opened by Notepad++"), TEXT("File open problem"), MB_OK|MB_APPLMODAL); */ fclose(fp); return false; } //Setup scratchtilla for new filedata _pscratchTilla->execute(SCI_SETSTATUS, SC_STATUS_OK); // reset error status _pscratchTilla->execute(SCI_SETDOCPOINTER, 0, doc); bool ro = _pscratchTilla->execute(SCI_GETREADONLY) != 0; if (ro) { _pscratchTilla->execute(SCI_SETREADONLY, false); } _pscratchTilla->execute(SCI_CLEARALL); if (language < L_EXTERNAL) { _pscratchTilla->execute(SCI_SETLEXER, ScintillaEditView::langNames[language].lexerID); } else { int id = language - L_EXTERNAL; TCHAR * name = NppParameters::getInstance()->getELCFromIndex(id)._name; WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); const char *pName = wmc->wchar2char(name, CP_ACP); _pscratchTilla->execute(SCI_SETLEXERLANGUAGE, 0, (LPARAM)pName); } if (encoding != -1) _pscratchTilla->execute(SCI_SETCODEPAGE, SC_CP_UTF8); bool success = true; FormatType format = FormatType::unknown; __try { // First allocate enough memory for the whole file (this will reduce memory copy during loading) _pscratchTilla->execute(SCI_ALLOCATE, WPARAM(bufferSizeRequested)); if (_pscratchTilla->execute(SCI_GETSTATUS) != SC_STATUS_OK) throw; size_t lenFile = 0; size_t lenConvert = 0; //just in case conversion results in 0, but file not empty bool isFirstTime = true; int incompleteMultibyteChar = 0; do { lenFile = fread(data+incompleteMultibyteChar, 1, blockSize-incompleteMultibyteChar, fp) + incompleteMultibyteChar; if (lenFile == 0) break; if (isFirstTime) { // check if file contain any BOM if (Utf8_16_Read::determineEncoding((unsigned char *)data, lenFile) != uni8Bit) { // if file contains any BOM, then encoding will be erased, // and the document will be interpreted as UTF encoding = -1; } else if (encoding == -1) { if (NppParameters::getInstance()->getNppGUI()._detectEncoding) encoding = detectCodepage(data, lenFile); } if (language == L_TEXT) { // check the language du fichier language = detectLanguageFromTextBegining((unsigned char *)data, lenFile); } isFirstTime = false; } if (encoding != -1) { if (encoding == SC_CP_UTF8) { // Pass through UTF-8 (this does not check validity of characters, thus inserting a multi-byte character in two halfs is working) _pscratchTilla->execute(SCI_APPENDTEXT, lenFile, (LPARAM)data); } else { WcharMbcsConvertor* wmc = WcharMbcsConvertor::getInstance(); int newDataLen = 0; const char *newData = wmc->encode(encoding, SC_CP_UTF8, data, lenFile, &newDataLen, &incompleteMultibyteChar); _pscratchTilla->execute(SCI_APPENDTEXT, newDataLen, (LPARAM)newData); } if (format == FormatType::unknown) format = getEOLFormatForm(data, lenFile, FormatType::unknown); } else { lenConvert = UnicodeConvertor->convert(data, lenFile); _pscratchTilla->execute(SCI_APPENDTEXT, lenConvert, (LPARAM)(UnicodeConvertor->getNewBuf())); } if (_pscratchTilla->execute(SCI_GETSTATUS) != SC_STATUS_OK) throw; if (incompleteMultibyteChar != 0) { // copy bytes to next buffer memcpy(data, data+blockSize-incompleteMultibyteChar, incompleteMultibyteChar); } } while (lenFile > 0); } __except(EXCEPTION_EXECUTE_HANDLER) //TODO: should filter correctly for other exceptions; the old filter(GetExceptionCode(), GetExceptionInformation()) was only catching access violations { ::MessageBox(NULL, TEXT("File is too big to be opened by Notepad++"), TEXT("File open problem"), MB_OK|MB_APPLMODAL); success = false; } fclose(fp); // broadcast the format if (pFormat != nullptr) *pFormat = (format != FormatType::unknown) ? format : FormatType::osdefault; _pscratchTilla->execute(SCI_EMPTYUNDOBUFFER); _pscratchTilla->execute(SCI_SETSAVEPOINT); if (ro) _pscratchTilla->execute(SCI_SETREADONLY, true); _pscratchTilla->execute(SCI_SETDOCPOINTER, 0, _scratchDocDefault); return success; }
BufferID FileManager::loadFile(const TCHAR * filename, Document doc, int encoding) { bool ownDoc = false; if (doc == NULL) { doc = (Document)_pscratchTilla->execute(SCI_CREATEDOCUMENT); ownDoc = true; } TCHAR fullpath[MAX_PATH]; ::GetFullPathName(filename, MAX_PATH, fullpath, NULL); ::GetLongPathName(fullpath, fullpath, MAX_PATH); Utf8_16_Read UnicodeConvertor; //declare here so we can get information after loading is done formatType format; bool res = loadFileData(doc, fullpath, &UnicodeConvertor, L_TEXT, encoding, &format); if (res) { Buffer * newBuf = new Buffer(this, _nextBufferID, doc, DOC_REGULAR, fullpath); BufferID id = (BufferID) newBuf; newBuf->_id = id; _buffers.push_back(newBuf); ++_nrBufs; Buffer * buf = _buffers.at(_nrBufs - 1); // restore the encoding (ANSI based) while opening the existing file NppParameters *pNppParamInst = NppParameters::getInstance(); const NewDocDefaultSettings & ndds = (pNppParamInst->getNppGUI()).getNewDocDefaultSettings(); buf->setUnicodeMode(ndds._encoding); buf->setEncoding(-1); if (encoding == -1) { // 3 formats : WIN_FORMAT, UNIX_FORMAT and MAC_FORMAT if (UnicodeConvertor.getNewBuf()) { int format = getEOLFormatForm(UnicodeConvertor.getNewBuf()); buf->setFormat(format == -1?WIN_FORMAT:(formatType)format); } else { buf->setFormat(WIN_FORMAT); } UniMode um = UnicodeConvertor.getEncoding(); if (um == uni7Bit) { if (ndds._openAnsiAsUtf8) { um = uniCookie; } else { um = uni8Bit; } } buf->setUnicodeMode(um); } else // encoding != -1 { // Test if encoding is set to UTF8 without BOM (usually for UTF-8 indicator of XML or HTML) buf->setEncoding((encoding == SC_CP_UTF8)?-1:encoding); buf->setUnicodeMode(uniCookie); buf->setFormat(format); } //determine buffer properties ++_nextBufferID; return id; } else //failed loading, release document { if (ownDoc) _pscratchTilla->execute(SCI_RELEASEDOCUMENT, 0, doc); //Failure, so release document return BUFFER_INVALID; } }