diff options
author | elfmz <fenix1905@tut.by> | 2022-02-07 02:22:40 +0300 |
---|---|---|
committer | elfmz <fenix1905@tut.by> | 2022-02-07 02:22:40 +0300 |
commit | 05994fed47189c33d53515f1c5682e55e235c3ae (patch) | |
tree | 649ae4f033aedb74c405c0db4a22a70af7e7c230 /far2l/src/fileedit.cpp | |
parent | aef68b79b183f7cbdf6d2e4f7b597b2077a47261 (diff) |
editor: make save file more tolerable to no space situation
Diffstat (limited to 'far2l/src/fileedit.cpp')
-rw-r--r-- | far2l/src/fileedit.cpp | 339 |
1 files changed, 171 insertions, 168 deletions
diff --git a/far2l/src/fileedit.cpp b/far2l/src/fileedit.cpp index 7fafbf39..1e0d5b96 100644 --- a/far2l/src/fileedit.cpp +++ b/far2l/src/fileedit.cpp @@ -1649,6 +1649,152 @@ int FileEditor::LoadFile(const wchar_t *Name,int &UserBreak) } //TextFormat и Codepage используются ТОЛЬКО, если bSaveAs = true! +void FileEditor::SaveContent(const wchar_t *Name, IContentWriter *Writer, bool bSaveAs, int TextFormat, UINT codepage, bool AddSignature) +{ + DWORD dwSignature = 0; + DWORD SignLength = 0; + switch (codepage) + { + case CP_UTF32LE: + dwSignature = SIGN_UTF32LE; + SignLength = 4; + if (!bSaveAs) AddSignature = (m_AddSignature != FB_NO); + break; + case CP_UTF32BE: + dwSignature = SIGN_UTF32BE; + SignLength = 4; + if (!bSaveAs) AddSignature = (m_AddSignature != FB_NO); + break; + case CP_UTF16LE: + dwSignature = SIGN_UTF16LE; + SignLength = 2; + if (!bSaveAs) AddSignature = (m_AddSignature != FB_NO); + break; + case CP_UTF16BE: + dwSignature = SIGN_UTF16BE; + SignLength = 2; + if (!bSaveAs) AddSignature = (m_AddSignature != FB_NO); + break; + case CP_UTF8: + dwSignature = SIGN_UTF8; + SignLength = 3; + if (!bSaveAs) AddSignature = (m_AddSignature == FB_YES); + break; + } + if (AddSignature) + Writer->Write(&dwSignature,SignLength); + + DWORD StartTime=WINPORT(GetTickCount)(); + size_t LineNumber=0; + + std::string tmpstr; + std::vector<unsigned char> tmpbuf; + + for (Edit *CurPtr=m_editor->TopList; CurPtr; CurPtr=CurPtr->m_next,LineNumber++) + { + DWORD CurTime=WINPORT(GetTickCount)(); + + if (CurTime-StartTime>RedrawTimeout) + { + StartTime=CurTime; + Editor::EditorShowMsg(MSG(MEditTitle),MSG(MEditSaving),Name,(int)(LineNumber*100/m_editor->NumLastLine)); + } + + const wchar_t *SaveStr, *EndSeq; + + int Length; + + CurPtr->GetBinaryString(&SaveStr,&EndSeq,Length); + + if (!*EndSeq && CurPtr->m_next) + EndSeq=*m_editor->GlobalEOL ? m_editor->GlobalEOL:DOS_EOL_fmt; + + if (TextFormat && *EndSeq) + { + EndSeq=m_editor->GlobalEOL; + CurPtr->SetEOL(EndSeq); + } + + int EndLength=StrLength(EndSeq); + if (codepage == CP_WIDE_LE) + { + if (Length) + Writer->Write(SaveStr,Length*sizeof(wchar_t)); + if (EndLength) + Writer->Write(EndSeq,EndLength*sizeof(wchar_t)); + } + else if (codepage == CP_UTF8) + { + Wide2MB(SaveStr, Length, tmpstr); + if (EndLength) + Wide2MB(EndSeq, EndLength, tmpstr, true); + if (!tmpstr.empty()) + Writer->Write(tmpstr.data(),tmpstr.size()); + } + else + { + if (Length) + { + const DWORD bufsize = (codepage == CP_WIDE_BE) ? Length * sizeof(wchar_t) + : WINPORT(WideCharToMultiByte)(codepage, 0, SaveStr, Length, nullptr, 0, nullptr, nullptr); + tmpbuf.resize(bufsize); + + if (codepage == CP_WIDE_BE) { + WideReverse(SaveStr, (wchar_t *)tmpbuf.data(), Length); + } else + WINPORT(WideCharToMultiByte)(codepage, 0, SaveStr, Length, (char *)tmpbuf.data(), bufsize, nullptr, nullptr); + + Writer->Write(tmpbuf.data(), bufsize); + } + + if (EndLength) + { + const DWORD bufsize = (codepage == CP_WIDE_BE ? EndLength*sizeof(wchar_t) + : WINPORT(WideCharToMultiByte)(codepage, 0, EndSeq, EndLength, nullptr, 0, nullptr, nullptr)); + tmpbuf.resize(bufsize); + if (codepage == CP_WIDE_BE) + WideReverse(EndSeq, (wchar_t *)tmpbuf.data(), EndLength); + else + WINPORT(WideCharToMultiByte)(codepage, 0, EndSeq, EndLength, (char *)tmpbuf.data(), bufsize, nullptr, nullptr); + + Writer->Write(tmpbuf.data(), bufsize); + } + } + } +} + + +struct ContentMeasurer : IContentWriter +{ + INT64 MeasuredSize = 0; + + virtual void Write(const void *Data, size_t Length) + { + MeasuredSize+= Length; + } +}; + +class ContentSaver : public IContentWriter +{ + CachedWrite CW; + +public: + ContentSaver(File &EditFile) : CW(EditFile) + { + } + + virtual void Write(const void *Data, size_t Length) + { + if (!CW.Write(Data, Length)) + throw WINPORT(GetLastError)(); + } + + void Flush() + { + if (!CW.Flush()) + throw WINPORT(GetLastError)(); + } +}; int FileEditor::SaveFile(const wchar_t *Name,int Ask, bool bSaveAs, int TextFormat, UINT codepage, bool AddSignature) { @@ -1872,16 +2018,6 @@ int FileEditor::SaveFile(const wchar_t *Name,int Ask, bool bSaveAs, int TextForm } CtrlObject->Plugins.ProcessEditorEvent(EE_SAVE,nullptr); - File EditFile; - DWORD dwWritten=0; - // Don't use CreationDisposition=CREATE_ALWAYS here - it's kills alternate streams - if(!EditFile.Open(Name, GENERIC_WRITE, FILE_SHARE_READ, nullptr, Flags.Check(FFILEEDIT_NEW)?CREATE_NEW:TRUNCATE_EXISTING, FILE_ATTRIBUTE_ARCHIVE|FILE_FLAG_SEQUENTIAL_SCAN)) - { - //_SVS(SysLogLastError();SysLog(L"Name='%ls',FileAttributes=%d",Name,FileAttributes)); - RetCode=SAVEFILE_ERROR; - SysErrorCode=WINPORT(GetLastError)(); - goto end; - } m_editor->UndoSavePos=m_editor->UndoPos; m_editor->Flags.Clear(FEDITOR_UNDOSAVEPOSLOST); @@ -1897,176 +2033,45 @@ int FileEditor::SaveFile(const wchar_t *Name,int Ask, bool bSaveAs, int TextForm SetCursorType(FALSE,0); TPreRedrawFuncGuard preRedrawFuncGuard(Editor::PR_EditorShowMsg); - DWORD dwSignature = 0; - DWORD SignLength = 0; - switch (codepage) - { - case CP_UTF32LE: - dwSignature = SIGN_UTF32LE; - SignLength = 4; - if (!bSaveAs) AddSignature = (m_AddSignature != FB_NO); - break; - case CP_UTF32BE: - dwSignature = SIGN_UTF32BE; - SignLength = 4; - if (!bSaveAs) AddSignature = (m_AddSignature != FB_NO); - break; - case CP_UTF16LE: - dwSignature = SIGN_UTF16LE; - SignLength = 2; - if (!bSaveAs) AddSignature = (m_AddSignature != FB_NO); - break; - case CP_UTF16BE: - dwSignature = SIGN_UTF16BE; - SignLength = 2; - if (!bSaveAs) AddSignature = (m_AddSignature != FB_NO); - break; - case CP_UTF8: - dwSignature = SIGN_UTF8; - SignLength = 3; - if (!bSaveAs) AddSignature = (m_AddSignature == FB_YES); - break; - } - if (AddSignature) - { - if (!EditFile.Write(&dwSignature,SignLength,&dwWritten,nullptr)||dwWritten!=SignLength) - { - EditFile.Close(); - apiDeleteFile(Name); - RetCode=SAVEFILE_ERROR; - goto end; - } - } - - DWORD StartTime=WINPORT(GetTickCount)(); - size_t LineNumber=0; - CachedWrite Cache(EditFile); + try { + ContentMeasurer cm; + SaveContent(Name, &cm, bSaveAs, TextFormat, codepage, AddSignature); - std::string tmpstr; + try { + File EditFile; + if (!EditFile.Open(Name, GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_ARCHIVE|FILE_FLAG_SEQUENTIAL_SCAN)) + throw WINPORT(GetLastError)(); - for (Edit *CurPtr=m_editor->TopList; CurPtr; CurPtr=CurPtr->m_next,LineNumber++) - { - DWORD CurTime=WINPORT(GetTickCount)(); - - if (CurTime-StartTime>RedrawTimeout) - { - StartTime=CurTime; - Editor::EditorShowMsg(MSG(MEditTitle),MSG(MEditSaving),Name,(int)(LineNumber*100/m_editor->NumLastLine)); - } - - const wchar_t *SaveStr, *EndSeq; - - int Length; - - CurPtr->GetBinaryString(&SaveStr,&EndSeq,Length); - - if (!*EndSeq && CurPtr->m_next) - EndSeq=*m_editor->GlobalEOL ? m_editor->GlobalEOL:DOS_EOL_fmt; - - if (TextFormat && *EndSeq) - { - EndSeq=m_editor->GlobalEOL; - CurPtr->SetEOL(EndSeq); - } - - int EndLength=StrLength(EndSeq); - bool bError = false; - - if (codepage == CP_WIDE_LE) - { - if ( - (Length && !Cache.Write(SaveStr,Length*sizeof(wchar_t))) || - (EndLength && !Cache.Write(EndSeq,EndLength*sizeof(wchar_t))) - ) + if (!Flags.Check(FFILEEDIT_NEW)) { - SysErrorCode=WINPORT(GetLastError)(); - bError = true; - } - } - else if (codepage == CP_UTF8) - { - Wide2MB(SaveStr, Length, tmpstr); - if (EndLength) - Wide2MB(EndSeq, EndLength, tmpstr, true); - if (!tmpstr.empty() && !Cache.Write(tmpstr.data(),tmpstr.size())) - bError = true; - } - else - { - if (Length) - { - DWORD length = (codepage == CP_WIDE_BE) ? Length * sizeof(wchar_t) : - WINPORT(WideCharToMultiByte)(codepage, 0, SaveStr, Length, nullptr, 0, nullptr, nullptr); - char *SaveStrCopy=(char *)malloc(length); - - if (SaveStrCopy) - { - if (codepage == CP_WIDE_BE) { - WideReverse(SaveStr, (wchar_t *)SaveStrCopy, Length); - } else - WINPORT(WideCharToMultiByte)(codepage, 0, SaveStr, Length, SaveStrCopy, length, nullptr, nullptr); - - if (!Cache.Write(SaveStrCopy,length)) - { - bError = true; - SysErrorCode=WINPORT(GetLastError)(); - } + if (!EditFile.SetPointer(cm.MeasuredSize, nullptr, FILE_BEGIN) || !EditFile.SetEnd()) + throw WINPORT(GetLastError)(); - free(SaveStrCopy); - } - else - bError = true; + EditFile.SetPointer(0, nullptr, FILE_BEGIN); } - if (!bError) - { - if (EndLength) - { - DWORD endlength = (codepage == CP_WIDE_BE ? EndLength*sizeof(wchar_t) - : WINPORT(WideCharToMultiByte)(codepage, 0, EndSeq, EndLength, nullptr, 0, nullptr, nullptr)); - char *EndSeqCopy=(char *)malloc(endlength); + ContentSaver cs(EditFile); + SaveContent(Name, &cs, bSaveAs, TextFormat, codepage, AddSignature); + cs.Flush(); - if (EndSeqCopy) - { - if (codepage == CP_WIDE_BE) - WideReverse(EndSeq, (wchar_t *)EndSeqCopy, EndLength); - else - WINPORT(WideCharToMultiByte)(codepage, 0, EndSeq, EndLength, EndSeqCopy, endlength, nullptr, nullptr); + EditFile.SetEnd(); - if (!Cache.Write(EndSeqCopy,endlength)) - { - bError = true; - SysErrorCode=WINPORT(GetLastError)(); - } + } catch (...) { + if (Flags.Check(FFILEEDIT_NEW)) + apiDeleteFile(Name); - free(EndSeqCopy); - } - else - bError = true; - } - } - } - - if (bError) - { - EditFile.Close(); - apiDeleteFile(Name); - RetCode=SAVEFILE_ERROR; - goto end; + throw; } } - - if(Cache.Flush()) + catch (DWORD ErrorCode) { - EditFile.SetEnd(); - EditFile.Close(); + SysErrorCode = ErrorCode; + RetCode = SAVEFILE_ERROR; } - else + catch (std::exception &e) { - SysErrorCode=WINPORT(GetLastError)(); - EditFile.Close(); - apiDeleteFile(Name); - RetCode=SAVEFILE_ERROR; + SysErrorCode = ENOMEM; + RetCode = SAVEFILE_ERROR; } } @@ -2074,8 +2079,6 @@ int FileEditor::SaveFile(const wchar_t *Name,int Ask, bool bSaveAs, int TextForm FileHolder->OnFileEdited(Name); } -end: - if (FileUnmakeWritable) { FileUnmakeWritable->Unmake(); |