/* viewer.cpp Internal viewer */ /* Copyright (c) 1996 Eugene Roshal Copyright (c) 2000 Far Group All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "headers.hpp" #pragma hdrstop #include "viewer.hpp" #include "codepage.hpp" #include "macroopcode.hpp" #include "keyboard.hpp" #include "flink.hpp" #include "lang.hpp" #include "colors.hpp" #include "keys.hpp" #include "help.hpp" #include "dialog.hpp" #include "panel.hpp" #include "filepanels.hpp" #include "fileview.hpp" #include "savefpos.hpp" #include "savescr.hpp" #include "ctrlobj.hpp" #include "scrbuf.hpp" #include "TPreRedrawFunc.hpp" #include "syslog.hpp" #include "TaskBar.hpp" #include "cddrv.hpp" #include "interf.hpp" #include "message.hpp" #include "clipboard.hpp" #include "delete.hpp" #include "dirmix.hpp" #include "pathmix.hpp" #include "filestr.hpp" #include "mix.hpp" #include "constitle.hpp" static void PR_ViewerSearchMsg(); static void ViewerSearchMsg(const wchar_t *Name,int Percent); static int InitHex=FALSE,SearchHex=FALSE; static int ViewerID=0; Viewer::Viewer(bool bQuickView, UINT aCodePage) { _OT(SysLog(L"[%p] Viewer::Viewer()", this)); m_bQuickView = bQuickView; ViOpt=Opt.ViOpt; for (int i=0; i<=MAXSCRY; i++) { Strings[i] = new ViewerString(); Strings[i]->lpData = new wchar_t[MAX_VIEWLINEB]; } strLastSearchStr = strGlobalSearchString; LastSearchCase=GlobalSearchCase; LastSearchRegexp=Opt.ViOpt.SearchRegexp; LastSearchWholeWords=GlobalSearchWholeWords; LastSearchReverse=GlobalSearchReverse; LastSearchHex=GlobalSearchHex; VM.CodePage=DefCodePage=aCodePage; // Вспомним тип врапа VM.Wrap=Opt.ViOpt.ViewerIsWrap; VM.WordWrap=Opt.ViOpt.ViewerWrap; VM.Hex=InitHex; ViewFile=NULL; ViewKeyBar=NULL; FilePos=0; LeftPos=0; SecondPos=0; FileSize=0; LastPage=0; SelectPos=SelectSize=0; LastSelPos=0; SetStatusMode(TRUE); HideCursor=TRUE; DeleteFolder=TRUE; CodePageChangedByUser=FALSE; ReadStdin=FALSE; memset(&BMSavePos,0xff,sizeof(BMSavePos)); memset(UndoData,0xff,sizeof(UndoData)); LastKeyUndo=FALSE; InternalKey=FALSE; Viewer::ViewerID=::ViewerID++; CtrlObject->Plugins.CurViewer=this; OpenFailed=false; HostFileViewer=NULL; SelectPosOffSet=0; bVE_READ_Sent = false; Signature = false; } Viewer::~Viewer() { KeepInitParameters(); if (ViewFile) { fclose(ViewFile); if (Opt.ViOpt.SavePos) { string strCacheName=strPluginData.IsEmpty()?strFullFileName:strPluginData+PointToName(strFileName); UINT CodePage=0; if (CodePageChangedByUser) { CodePage=VM.CodePage; } PosCache poscache={0}; poscache.Param[0]=FilePos; poscache.Param[1]=LeftPos; poscache.Param[2]=VM.Hex; //=poscache.Param[3]; poscache.Param[4]=CodePage; if (Opt.ViOpt.SaveShortPos) { poscache.Position[0]=BMSavePos.SavePosAddr; poscache.Position[1]=BMSavePos.SavePosLeft; //poscache.Position[2]=; //poscache.Position[3]=; } CtrlObject->ViewerPosCache->AddPosition(strCacheName,poscache); } } _tran(SysLog(L"[%p] Viewer::~Viewer, TempViewName=[%s]",this,TempViewName)); /* $ 11.10.2001 IS Удаляем файл только, если нет открытых фреймов с таким именем. */ if (!strTempViewName.IsEmpty() && !FrameManager->CountFramesWithName(strTempViewName)) { /* $ 14.06.2002 IS Если DeleteFolder сброшен, то удаляем только файл. Иначе - удаляем еще и каталог. */ if (DeleteFolder) DeleteFileWithFolder(strTempViewName); else { apiSetFileAttributes(strTempViewName,FILE_ATTRIBUTE_NORMAL); apiDeleteFile(strTempViewName); //BUGBUG } } for (int i=0; i<=MAXSCRY; i++) { delete [] Strings[i]->lpData; delete Strings[i]; } if (!OpenFailed && bVE_READ_Sent) { CtrlObject->Plugins.CurViewer=this; //HostFileViewer; CtrlObject->Plugins.ProcessViewerEvent(VE_CLOSE,&ViewerID); } } void Viewer::KeepInitParameters() { strGlobalSearchString = strLastSearchStr; GlobalSearchCase=LastSearchCase; GlobalSearchWholeWords=LastSearchWholeWords; GlobalSearchReverse=LastSearchReverse; GlobalSearchHex=LastSearchHex; Opt.ViOpt.ViewerIsWrap=VM.Wrap; Opt.ViOpt.ViewerWrap=VM.WordWrap; Opt.ViOpt.SearchRegexp=LastSearchRegexp; InitHex=VM.Hex; } int Viewer::OpenFile(const wchar_t *Name,int warning) { VM.CodePage=DefCodePage; DefCodePage=CP_AUTODETECT; FILE *NewViewFile=NULL; OpenFailed=false; if (ViewFile) fclose(ViewFile); ViewFile=NULL; SelectSize = 0; // Сбросим выделение strFileName = Name; if (Opt.OnlyEditorViewerUsed && StrCmp(strFileName, L"-")==0) { string strTempName; if (!FarMkTempEx(strTempName)) { OpenFailed=TRUE; return(FALSE); } HANDLE OutHandle=apiCreateFile(strTempName,GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE); if (OutHandle==INVALID_HANDLE_VALUE) { OpenFailed=true; return(FALSE); } char ReadBuf[8192]; DWORD ReadSize,WrittenSize; while (ReadFile(GetStdHandle(STD_INPUT_HANDLE),ReadBuf,sizeof(ReadBuf),&ReadSize,NULL)) WriteFile(OutHandle,ReadBuf,ReadSize,&WrittenSize,NULL); //after reading from the pipe, redirect stdin to the real console stdin HANDLE hConin=CreateFile(L"CONIN$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,0,0); SetStdHandle(STD_INPUT_HANDLE,hConin); int InpHandle=_open_osfhandle((intptr_t)OutHandle,O_BINARY); if (InpHandle!=-1) NewViewFile=_fdopen(InpHandle,"rb"); vseek(NewViewFile,0,SEEK_SET); ReadStdin=TRUE; } else { NewViewFile=NULL; HANDLE hView=apiCreateFile(strFileName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0); if (hView!=INVALID_HANDLE_VALUE) { int ViewHandle=_open_osfhandle((intptr_t)hView,O_BINARY); if (ViewHandle == -1) CloseHandle(hView); else { NewViewFile=_fdopen(ViewHandle,"rb"); if (NewViewFile==NULL) _close(ViewHandle); } } } if (NewViewFile==NULL) { /* $ 04.07.2000 tran + 'warning' flag processing, in QuickView it is FALSE so don't show red message box */ if (warning) Message(MSG_WARNING|MSG_ERRORTYPE,1,MSG(MViewerTitle), MSG(MViewerCannotOpenFile),strFileName,MSG(MOk)); OpenFailed=true; return(FALSE); } CodePageChangedByUser=FALSE; ViewFile=NewViewFile; ConvertNameToFull(strFileName,strFullFileName); apiGetFindDataEx(strFileName, &ViewFindData); UINT CachedCodePage=0; if (Opt.ViOpt.SavePos && !ReadStdin) { __int64 NewLeftPos,NewFilePos; string strCacheName=strPluginData.IsEmpty()?strFileName:strPluginData+PointToName(strFileName); memset(&BMSavePos,0xff,sizeof(BMSavePos)); //заполним с -1 PosCache poscache={0}; if (Opt.ViOpt.SaveShortPos) { poscache.Position[0]=BMSavePos.SavePosAddr; poscache.Position[1]=BMSavePos.SavePosLeft; //poscache.Position[2]=; //poscache.Position[3]=; } CtrlObject->ViewerPosCache->GetPosition(strCacheName,poscache); NewFilePos=poscache.Param[0]; NewLeftPos=poscache.Param[1]; VM.Hex=(int)poscache.Param[2]; //=poscache.Param[3]; CachedCodePage=(UINT)poscache.Param[4]; // Проверяем поддерживается или нет загруженная из кэша кодовая страница if (CachedCodePage && !IsCodePageSupported(CachedCodePage)) CachedCodePage = 0; LastSelPos=FilePos=NewFilePos; LeftPos=NewLeftPos; } else FilePos=0; /* $ 26.07.2002 IS Автоопределение Unicode не должно зависеть от опции "Автоопределение таблицы символов", т.к. Unicode не есть _таблица символов_ для перекодировки. */ //if(ViOpt.AutoDetectTable) { bool Detect=false; UINT CodePage=0; if (VM.CodePage == CP_AUTODETECT || IsUnicodeOrUtfCodePage(VM.CodePage)) { Detect=GetFileFormat(ViewFile,CodePage,&Signature,Opt.ViOpt.AutoDetectCodePage!=0); // Проверяем поддерживается или нет задетектированная кодовая страница if (Detect) Detect = IsCodePageSupported(CodePage); } if (VM.CodePage==CP_AUTODETECT) { if (Detect) { VM.CodePage=CodePage; } if (CachedCodePage) { VM.CodePage=CachedCodePage; CodePageChangedByUser=TRUE; } if (VM.CodePage==CP_AUTODETECT) VM.CodePage=Opt.ViOpt.AnsiCodePageAsDefault?GetACP():GetOEMCP(); } else { CodePageChangedByUser=TRUE; } // BUGBUG // пока что запретим переключать hex в UTF8, ибо не работает. if (VM.Hex && VM.CodePage==CP_UTF8) { VM.CodePage=Opt.ViOpt.AnsiCodePageAsDefault?GetACP():GetOEMCP(); } if (!IsUnicodeOrUtfCodePage(VM.CodePage)) fseek(ViewFile,0,SEEK_SET); } SetFileSize(); if (FilePos>FileSize) FilePos=0; SetCRSym(); // if (ViOpt.AutoDetectTable && !TableChangedByUser) // { // } ChangeViewKeyBar(); AdjustWidth(); CtrlObject->Plugins.CurViewer=this; // HostFileViewer; /* $ 15.09.2001 tran пора легализироваться */ CtrlObject->Plugins.ProcessViewerEvent(VE_READ,NULL); bVE_READ_Sent = true; return(TRUE); } /* $ 27.04.2001 DJ функция вычисления ширины в зависимости от наличия скроллбара */ void Viewer::AdjustWidth() { Width=X2-X1+1; XX2=X2; if (ViOpt.ShowScrollbar && !m_bQuickView) { Width--; XX2--; } } void Viewer::SetCRSym() { if (!ViewFile) return; wchar_t Buf[2048]; int CRCount=0,LFCount=0; int ReadSize,I; vseek(ViewFile,0,SEEK_SET); ReadSize=vread(Buf,countof(Buf),ViewFile); for (I=0; I=ReadSize || Buf[I+1]!=L'\n') CRCount++; break; } if (LFCountPlugins.CurViewer = this; //HostFileViewer; ShowHex(); break; case SHOW_RELOAD: CtrlObject->Plugins.CurViewer = this; //HostFileViewer; for (I=0,Y=Y1; Y<=Y2; Y++,I++) { Strings[I]->nFilePos = vtell(ViewFile); if (Y==Y1+1 && !feof(ViewFile)) SecondPos=vtell(ViewFile); ReadString(Strings[I],-1,MAX_VIEWLINEB); } break; case SHOW_UP: for (I=Y2-Y1-1; I>=0; I--) { Strings[I+1]->nFilePos = Strings[I]->nFilePos; Strings[I+1]->nSelStart = Strings[I]->nSelStart; Strings[I+1]->nSelEnd = Strings[I]->nSelEnd; Strings[I+1]->bSelection = Strings[I]->bSelection; wcscpy(Strings[I+1]->lpData, Strings[I]->lpData); } Strings[0]->nFilePos = FilePos; SecondPos = Strings[1]->nFilePos; ReadString(Strings[0],(int)(SecondPos-FilePos),MAX_VIEWLINEB); break; case SHOW_DOWN: for (I=0; InFilePos = Strings[I+1]->nFilePos; Strings[I]->nSelStart = Strings[I+1]->nSelStart; Strings[I]->nSelEnd = Strings[I+1]->nSelEnd; Strings[I]->bSelection = Strings[I+1]->bSelection; wcscpy(Strings[I]->lpData, Strings[I+1]->lpData); } FilePos = Strings[0]->nFilePos; SecondPos = Strings[1]->nFilePos; vseek(ViewFile, Strings[Y2-Y1]->nFilePos, SEEK_SET); ReadString(Strings[Y2-Y1],-1,MAX_VIEWLINEB); Strings[Y2-Y1]->nFilePos = vtell(ViewFile); ReadString(Strings[Y2-Y1],-1,MAX_VIEWLINEB); break; } if (nMode != SHOW_HEX) { for (I=0,Y=Y1; Y<=Y2; Y++,I++) { int StrLen = StrLength(Strings[I]->lpData); SetColor(COL_VIEWERTEXT); GotoXY(X1,Y); if (StrLen > LeftPos) { if (IsUnicodeOrUtfCodePage(VM.CodePage) && Signature && !I && !Strings[I]->nFilePos) { FS<lpData[static_cast(LeftPos+1)]; } else { FS<lpData[static_cast(LeftPos)]; } } else { FS<bSelection) { __int64 SelX1; if (LeftPos > Strings[I]->nSelStart) SelX1 = X1; else SelX1 = Strings[I]->nSelStart-LeftPos; if (!VM.Wrap && (Strings[I]->nSelStart < LeftPos || Strings[I]->nSelStart > LeftPos+XX2-X1)) { if (AdjustSelPosition) { LeftPos = Strings[I]->nSelStart-1; AdjustSelPosition = FALSE; Show(); return; } } else { SetColor(COL_VIEWERSELECTEDTEXT); GotoXY(static_cast(X1+SelX1),Y); __int64 Length = Strings[I]->nSelEnd-Strings[I]->nSelStart; if (LeftPos > Strings[I]->nSelStart) Length = Strings[I]->nSelEnd-LeftPos; if (LeftPos > Strings[I]->nSelEnd) Length = 0; FS<(Length))<<&Strings[I]->lpData[static_cast(SelX1+LeftPos+SelectPosOffSet)]; } } if (StrLen > LeftPos + Width && ViOpt.ShowArrows) { GotoXY(XX2,Y); SetColor(COL_VIEWERARROWS); BoxText(0xbb); } if (LeftPos>0 && *Strings[I]->lpData!=0 && ViOpt.ShowArrows) { GotoXY(X1,Y); SetColor(COL_VIEWERARROWS); BoxText(0xab); } } } DrawScrollbar(); ShowStatus(); } void Viewer::DisplayObject() { ShowPage(VM.Hex?SHOW_HEX:SHOW_RELOAD); } void Viewer::ShowHex() { wchar_t OutStr[MAX_VIEWLINE],TextStr[20]; int EndFile; __int64 SelSize; WCHAR Ch; int X,Y,TextPos; int SelStart, SelEnd; bool bSelStartFound = false, bSelEndFound = false; __int64 HexLeftPos=((LeftPos>80-ObjWidth) ? Max(80-ObjWidth,0):LeftPos); for (EndFile=0,Y=Y1; Y<=Y2; Y++) { bSelStartFound = false; bSelEndFound = false; SelSize=0; SetColor(COL_VIEWERTEXT); GotoXY(X1,Y); if (EndFile) { FS< SelectPos) bSelStartFound = true; if (fpos < SelectPos+SelectSize-1) bSelEndFound = true; if (!SelectSize) bSelStartFound = bSelEndFound = false; const wchar_t BorderLine[]={BoxSymbols[BS_V1],L' ',0}; if (IsUnicodeCodePage(VM.CodePage)) { for (X=0; X<8; X++) { __int64 fpos = vtell(ViewFile); if (SelectSize>0 && (SelectPos == fpos)) { bSelStartFound = true; SelStart = (int)wcslen(OutStr); SelSize=SelectSize; /* $ 22.01.2001 IS Внимание! Возможно, это не совсем верное решение проблемы выделения из плагинов, но мне пока другого в голову не пришло. Я приравниваю SelectSize нулю в Process* */ //SelectSize=0; } if (SelectSize>0 && (fpos == (SelectPos+SelectSize-1))) { bSelEndFound = true; SelEnd = (int)wcslen(OutStr)+3; SelSize=SelectSize; } if (!vgetc(ViewFile,Ch)) { /* $ 28.06.2000 tran убираем показ пустой строки, если длина файла кратна 16 */ EndFile=1; LastPage=1; if (X==0) { wcscpy(OutStr,L""); break; } wcscat(OutStr,L" "); TextStr[TextPos++]=L' '; } else { WCHAR OutChar=Ch; if (VM.CodePage == CP_REVERSEBOM) { _swab(reinterpret_cast(&OutChar),reinterpret_cast(&OutChar),sizeof(WCHAR)); } int OutStrLen=StrLength(OutStr); _snwprintf(OutStr+OutStrLen,countof(OutStr)-OutStrLen,L"%02X%02X ",HIBYTE(OutChar),LOBYTE(OutChar)); if (!Ch) { Ch=L' '; } TextStr[TextPos++]=Ch; LastPage=0; } if (X==3) wcscat(OutStr, BorderLine); } } else { for (X=0; X<16; X++) { __int64 fpos = vtell(ViewFile); if (SelectSize>0 && (SelectPos == fpos)) { bSelStartFound = true; SelStart = (int)wcslen(OutStr); SelSize=SelectSize; /* $ 22.01.2001 IS Внимание! Возможно, это не совсем верное решение проблемы выделения из плагинов, но мне пока другого в голову не пришло. Я приравниваю SelectSize нулю в Process* */ //SelectSize=0; } if (SelectSize>0 && (fpos == (SelectPos+SelectSize-1))) { bSelEndFound = true; SelEnd = (int)wcslen(OutStr)+1; SelSize=SelectSize; } if (!vgetc(ViewFile,Ch)) { /* $ 28.06.2000 tran убираем показ пустой строки, если длина файла кратна 16 */ EndFile=1; LastPage=1; if (X==0) { wcscpy(OutStr,L""); break; } /* $ 03.07.2000 tran - вместо 5 пробелов тут надо 3 */ wcscat(OutStr,L" "); TextStr[TextPos++]=L' '; } else { char NewCh; WideCharToMultiByte(VM.CodePage, 0, &Ch,1, &NewCh,1," ",NULL); int OutStrLen=StrLength(OutStr); _snwprintf(OutStr+OutStrLen,countof(OutStr)-OutStrLen,L"%02X ", NewCh); if (Ch==0) Ch=L' '; TextStr[TextPos++]=Ch; LastPage=0; } if (X==7) wcscat(OutStr,BorderLine); } } TextStr[TextPos]=0; wcscat(TextStr,L" "); if ((SelEnd <= SelStart) && bSelStartFound) SelEnd = (int)wcslen(OutStr)-2; wcscat(OutStr,L" "); wcscat(OutStr,TextStr); #if 0 for (size_t I=0; I < wcslen(OutStr); ++I) if (OutStr[I] == (wchar_t)0xFFFF) OutStr[I]=L'?'; #endif if (StrLength(OutStr)>HexLeftPos) { FS<(HexLeftPos); } else { FS<(SelStart); SelSize = 0; } } } /* $ 27.04.2001 DJ отрисовка скроллбара - в отдельную функцию */ void Viewer::DrawScrollbar() { if (ViOpt.ShowScrollbar) { if (m_bQuickView) SetColor(COL_PANELSCROLLBAR); else SetColor(COL_VIEWERSCROLLBAR); if (!VM.Hex) { ScrollBar(X2+(m_bQuickView?1:0),Y1,Y2-Y1+1,(LastPage != 0? (!FilePos?0:100):ToPercent64(FilePos,FileSize)),100); } else { UINT64 Total=FileSize/16+(FileSize%16?1:0); UINT64 Top=FilePos/16+(FilePos%16?1:0); ScrollBarEx(X2+(m_bQuickView?1:0),Y1,Y2-Y1+1,LastPage?Top?Total:0:Top,Total); } } } string &Viewer::GetTitle(string &strName,int,int) { if (!strTitle.IsEmpty()) { strName = strTitle; } else { if (!IsAbsolutePath(strFileName)) { string strPath; ViewNamesList.GetCurDir(strPath); AddEndSlash(strPath); strName = strPath+strFileName; } else { strName = strFileName; } } return strName; } void Viewer::ShowStatus() { if (HostFileViewer) HostFileViewer->ShowStatus(); } void Viewer::SetStatusMode(int Mode) { ShowStatusLine=Mode; } void Viewer::ReadString(ViewerString *pString, int MaxSize, int StrSize) { WCHAR Ch, Ch2; __int64 OutPtr; bool bSelStartFound = false, bSelEndFound = false; pString->bSelection = false; AdjustWidth(); OutPtr=0; if (VM.Hex) { OutPtr=vread(pString->lpData,IsUnicodeCodePage(VM.CodePage) ? 8:16,ViewFile); pString->lpData[IsUnicodeCodePage(VM.CodePage) ? 8:16]=0; } else { bool CRSkipped=false; if (SelectSize && vtell(ViewFile) > SelectPos) { pString->nSelStart = 0; bSelStartFound = true; } for (;;) { if (OutPtr>=StrSize-16) break; /* $ 12.07.2000 SVS ! Wrap - трехпозиционный */ if (VM.Wrap && OutPtr>XX2-X1) { /* $ 11.07.2000 tran + warp are now WORD-WRAP */ __int64 SavePos=vtell(ViewFile); WCHAR TmpChar=0; if (vgetc(ViewFile,Ch) && Ch!=CRSym && (Ch!=L'\r' || (vgetc(ViewFile,TmpChar) && TmpChar!=CRSym))) { vseek(ViewFile,SavePos,SEEK_SET); if (VM.WordWrap) { if (!IsSpace(Ch) && !IsSpace(pString->lpData[(int)OutPtr])) { __int64 SavePtr=OutPtr; /* $ 18.07.2000 tran добавил в качестве wordwrap разделителей , ; > ) */ while (OutPtr) { Ch2=pString->lpData[(int)OutPtr]; if (IsSpace(Ch2) || Ch2==L',' || Ch2==L';' || Ch2==L'>'|| Ch2==L')') break; OutPtr--; } Ch2=pString->lpData[(int)OutPtr]; if (Ch2==L',' || Ch2==L';' || Ch2==L')' || Ch2==L'>') OutPtr++; else while (IsSpace(pString->lpData[(int)OutPtr]) && OutPtr<=SavePtr) OutPtr++; if (OutPtr) { vseek(ViewFile,OutPtr-SavePtr,SEEK_CUR); // } else OutPtr=SavePtr; } /* $ 13.09.2000 tran remove space at WWrap */ __int64 savepos=vtell(ViewFile); while (IsSpace(Ch)) { if (!vgetc(ViewFile,Ch)) { break; } } if (vtell(ViewFile)!=savepos) vseek(ViewFile,-1,SEEK_CUR); }// wwrap } break; } if (SelectSize > 0 && SelectPos==vtell(ViewFile)) { pString->nSelStart = OutPtr+(CRSkipped?1:0);; bSelStartFound = true; } if (MaxSize-- == 0) break; if (!vgetc(ViewFile,Ch)) break; if (Ch==CRSym) break; if (CRSkipped) { CRSkipped=false; pString->lpData[(int)OutPtr++]=L'\r'; } if (Ch==L'\t') { do { pString->lpData[(int)OutPtr++]=L' '; } while ((OutPtr % ViOpt.TabSize)!=0 && ((int)OutPtr < (MAX_VIEWLINEB-1))); if (VM.Wrap && OutPtr>XX2-X1) pString->lpData[XX2-X1+1]=0; continue; } /* $ 20.09.01 IS Баг: не учитывали левую границу при свертке */ if (Ch==L'\r') { CRSkipped=true; if (OutPtr>=XX2-X1) { __int64 SavePos=vtell(ViewFile); WCHAR nextCh=0; if (vgetc(ViewFile,nextCh) && nextCh!=CRSym) { CRSkipped=false; } vseek(ViewFile,SavePos,SEEK_SET); } if (CRSkipped) continue; } if (Ch==0 || Ch==L'\n') Ch=L' '; pString->lpData[(int)OutPtr++]=Ch; pString->lpData[(int)OutPtr]=0; if (SelectSize > 0 && (SelectPos+SelectSize)==vtell(ViewFile)) { pString->nSelEnd = OutPtr; bSelEndFound = true; } } } pString->lpData[(int)OutPtr]=0; if (!bSelEndFound && SelectSize && vtell(ViewFile) < SelectPos+SelectSize) { bSelEndFound = true; pString->nSelEnd = wcslen(pString->lpData); } if (bSelStartFound) { if (pString->nSelStart > (__int64)wcslen(pString->lpData)) bSelStartFound = false; if (bSelEndFound) if (pString->nSelStart > pString->nSelEnd) bSelStartFound = false; } LastPage=feof(ViewFile); if (bSelStartFound && bSelEndFound) pString->bSelection = true; } __int64 Viewer::VMProcess(int OpCode,void *vParam,__int64 iParam) { switch (OpCode) { case MCODE_C_EMPTY: return (__int64)(FileSize==0); case MCODE_C_SELECTED: return (__int64)(SelectSize==0?FALSE:TRUE); case MCODE_C_EOF: return (__int64)(LastPage || ViewFile==NULL); case MCODE_C_BOF: return (__int64)(!FilePos || ViewFile==NULL); case MCODE_V_VIEWERSTATE: { DWORD MacroViewerState=0; MacroViewerState|=VM.Wrap?0x00000008:0; MacroViewerState|=VM.WordWrap?0x00000010:0; MacroViewerState|=VM.Hex?0x00000020:0; MacroViewerState|=Opt.OnlyEditorViewerUsed?0x08000000:0; MacroViewerState|=HostFileViewer && !HostFileViewer->GetCanLoseFocus()?0x00000800:0; return (__int64)MacroViewerState; } case MCODE_V_ITEMCOUNT: // ItemCount - число элементов в текущем объекте return (__int64)GetViewFileSize(); case MCODE_V_CURPOS: // CurPos - текущий индекс в текущем объекте return (__int64)(GetViewFilePos()+1); } return 0; } /* $ 28.01.2001 - Путем проверки ViewFile на NULL избавляемся от падения */ int Viewer::ProcessKey(int Key) { ViewerString vString; /* $ 22.01.2001 IS Происходят какие-то манипуляции -> снимем выделение */ if (!ViOpt.PersistentBlocks && Key!=KEY_IDLE && Key!=KEY_NONE && !(Key==KEY_CTRLINS||Key==KEY_CTRLNUMPAD0) && Key!=KEY_CTRLC) SelectSize=0; if (!InternalKey && !LastKeyUndo && (FilePos!=UndoData[0].UndoAddr || LeftPos!=UndoData[0].UndoLeft)) { for (int i=countof(UndoData)-1; i>0; i--) { UndoData[i].UndoAddr=UndoData[i-1].UndoAddr; UndoData[i].UndoLeft=UndoData[i-1].UndoLeft; } UndoData[0].UndoAddr=FilePos; UndoData[0].UndoLeft=LeftPos; } if (Key!=KEY_ALTBS && Key!=KEY_CTRLZ && Key!=KEY_NONE && Key!=KEY_IDLE) LastKeyUndo=FALSE; if (Key>=KEY_CTRL0 && Key<=KEY_CTRL9) { int Pos=Key-KEY_CTRL0; if (BMSavePos.SavePosAddr[Pos]!=POS_NONE) { FilePos=BMSavePos.SavePosAddr[Pos]; LeftPos=BMSavePos.SavePosLeft[Pos]; // LastSelPos=FilePos; Show(); } return(TRUE); } if (Key>=KEY_CTRLSHIFT0 && Key<=KEY_CTRLSHIFT9) Key=Key-KEY_CTRLSHIFT0+KEY_RCTRL0; if (Key>=KEY_RCTRL0 && Key<=KEY_RCTRL9) { int Pos=Key-KEY_RCTRL0; BMSavePos.SavePosAddr[Pos]=FilePos; BMSavePos.SavePosLeft[Pos]=LeftPos; return(TRUE); } switch (Key) { case KEY_F1: { Help Hlp(L"Viewer"); return(TRUE); } case KEY_CTRLU: { // if (SelectSize) { SelectSize = 0; Show(); } return(TRUE); } case KEY_CTRLC: case KEY_CTRLINS: case KEY_CTRLNUMPAD0: { if (SelectSize && ViewFile) { wchar_t *SelData; size_t DataSize = (size_t)SelectSize+(IsUnicodeCodePage(VM.CodePage)?sizeof(wchar_t):1); __int64 CurFilePos=vtell(ViewFile); if ((SelData=(wchar_t*)xf_malloc(DataSize*sizeof(wchar_t))) != NULL) { wmemset(SelData, 0, DataSize); vseek(ViewFile,SelectPos,SEEK_SET); vread(SelData, (int)SelectSize, ViewFile); CopyToClipboard(SelData); xf_free(SelData); vseek(ViewFile,CurFilePos,SEEK_SET); } } return(TRUE); } // включить/выключить скролбар case KEY_CTRLS: { ViOpt.ShowScrollbar=!ViOpt.ShowScrollbar; Opt.ViOpt.ShowScrollbar=ViOpt.ShowScrollbar; if (m_bQuickView) CtrlObject->Cp()->ActivePanel->Redraw(); Show(); return (TRUE); } case KEY_IDLE: { if (ViewFile) { string strRoot; GetPathRoot(strFullFileName, strRoot); int DriveType=FAR_GetDriveType(strRoot); if (DriveType!=DRIVE_REMOVABLE && !IsDriveTypeCDROM(DriveType)) { FAR_FIND_DATA_EX NewViewFindData; if (!apiGetFindDataEx(strFullFileName,&NewViewFindData)) return TRUE; fflush(ViewFile); vseek(ViewFile,0,SEEK_END); __int64 CurFileSize=vtell(ViewFile); if (ViewFindData.ftLastWriteTime.dwLowDateTime!=NewViewFindData.ftLastWriteTime.dwLowDateTime || ViewFindData.ftLastWriteTime.dwHighDateTime!=NewViewFindData.ftLastWriteTime.dwHighDateTime || CurFileSize!=FileSize) { ViewFindData=NewViewFindData; FileSize=CurFileSize; if (FilePos>FileSize) ProcessKey(KEY_CTRLEND); else { __int64 PrevLastPage=LastPage; Show(); if (PrevLastPage && !LastPage) { ProcessKey(KEY_CTRLEND); LastPage=TRUE; } } } } } if (Opt.ViewerEditorClock && HostFileViewer!=NULL && HostFileViewer->IsFullScreen() && Opt.ViOpt.ShowTitleBar) ShowTime(FALSE); return(TRUE); } case KEY_ALTBS: case KEY_CTRLZ: { for (size_t I=1; IViewerPosCache->AddPosition(strCacheName,poscache); memset(&BMSavePos,0xff,sizeof(BMSavePos)); //??!!?? } } if (PointToName(strName) == strName) { string strViewDir; ViewNamesList.GetCurDir(strViewDir); if (!strViewDir.IsEmpty()) FarChDir(strViewDir); } if (OpenFile(strName, TRUE)) { SecondPos=0; Show(); } ShowConsoleTitle(); } } return(TRUE); } case KEY_SHIFTF2: { ProcessTypeWrapMode(!VM.WordWrap); return TRUE; } case KEY_F2: { ProcessWrapMode(!VM.Wrap); return(TRUE); } case KEY_F4: { ProcessHexMode(!VM.Hex); return(TRUE); } case KEY_F7: { Search(0,0); return(TRUE); } case KEY_SHIFTF7: case KEY_SPACE: { Search(1,0); return(TRUE); } case KEY_ALTF7: { SearchFlags.Set(REVERSE_SEARCH); Search(1,0); SearchFlags.Clear(REVERSE_SEARCH); return(TRUE); } case KEY_F8: { if (IsUnicodeCodePage(VM.CodePage)) { FilePos*=2; SetFileSize(); SelectPos = 0; SelectSize = 0; } VM.CodePage = VM.CodePage==GetOEMCP() ? GetACP() : GetOEMCP(); ChangeViewKeyBar(); Show(); // LastSelPos=FilePos; CodePageChangedByUser=TRUE; return(TRUE); } case KEY_SHIFTF8: { UINT nCodePage = SelectCodePage(VM.CodePage, true, true); // BUGBUG // пока что запретим переключать hex в UTF8, ибо не работает. if (VM.Hex && nCodePage==CP_UTF8) { return(TRUE); } if (nCodePage!=(UINT)-1) { CodePageChangedByUser=TRUE; if (IsUnicodeCodePage(VM.CodePage) && !IsUnicodeCodePage(nCodePage)) { FilePos*=2; SelectPos = 0; SelectSize = 0; SetCRSym(); } else if (!IsUnicodeCodePage(VM.CodePage) && IsUnicodeCodePage(nCodePage)) { FilePos=(FilePos+(FilePos&1))/2; //???? SelectPos = 0; SelectSize = 0; SetCRSym(); } VM.CodePage=nCodePage; SetFileSize(); ChangeViewKeyBar(); Show(); // LastSelPos=FilePos; } return(TRUE); } case KEY_ALTF8: { if (ViewFile) GoTo(); return(TRUE); } case KEY_F11: { CtrlObject->Plugins.CommandsMenu(MODALTYPE_VIEWER,0,L"Viewer"); Show(); return(TRUE); } /* $ 27.06.2001 VVM + С альтом скролим по 1 */ case KEY_MSWHEEL_UP: case(KEY_MSWHEEL_UP | KEY_ALT): { int Roll = Key & KEY_ALT?1:Opt.MsWheelDeltaView; for (int i=0; i0 && ViewFile) { Up(); if (VM.Hex) { FilePos&=~(IsUnicodeCodePage(VM.CodePage) ? 0x7:0xf); Show(); } else ShowPage(SHOW_UP); } // LastSelPos=FilePos; return(TRUE); } case KEY_DOWN: case KEY_NUMPAD2: case KEY_SHIFTNUMPAD2: { if (!LastPage && ViewFile) { if (VM.Hex) { FilePos=SecondPos; Show(); } else ShowPage(SHOW_DOWN); } // LastSelPos=FilePos; return(TRUE); } case KEY_PGUP: case KEY_NUMPAD9: case KEY_SHIFTNUMPAD9: case KEY_CTRLUP: { if (ViewFile) { for (int i=Y1; i0 && ViewFile) { if (VM.Hex && LeftPos>80-Width) LeftPos=Max(80-Width,1); LeftPos--; Show(); } // LastSelPos=FilePos; return(TRUE); } case KEY_RIGHT: case KEY_NUMPAD6: case KEY_SHIFTNUMPAD6: { if (LeftPos= FileSize) FilePos=FileSize-1; //?? } else if (!VM.Wrap) { LeftPos+=20; if (LeftPos>MAX_VIEWLINE) LeftPos=MAX_VIEWLINE; } Show(); // LastSelPos=FilePos; } return(TRUE); } case KEY_CTRLSHIFTLEFT: case KEY_CTRLSHIFTNUMPAD4: // Перейти на начало строк if (ViewFile) { LeftPos = 0; Show(); } return(TRUE); case KEY_CTRLSHIFTRIGHT: case KEY_CTRLSHIFTNUMPAD6: { // Перейти на конец строк if (ViewFile) { int I, Y, Len, MaxLen = 0; for (I=0,Y=Y1; Y<=Y2; Y++,I++) { Len = StrLength(Strings[I]->lpData); if (Len > MaxLen) MaxLen = Len; } /* for */ if (MaxLen > Width) LeftPos = MaxLen - Width; else LeftPos = 0; Show(); } /* if */ return(TRUE); } case KEY_CTRLHOME: case KEY_CTRLNUMPAD7: case KEY_HOME: case KEY_NUMPAD7: case KEY_SHIFTNUMPAD7: // Перейти на начало файла if (ViewFile) LeftPos=0; case KEY_CTRLPGUP: case KEY_CTRLNUMPAD9: if (ViewFile) { FilePos=0; Show(); // LastSelPos=FilePos; } return(TRUE); case KEY_CTRLEND: case KEY_CTRLNUMPAD1: case KEY_END: case KEY_NUMPAD1: case KEY_SHIFTNUMPAD1: // Перейти на конец файла if (ViewFile) LeftPos=0; case KEY_CTRLPGDN: case KEY_CTRLNUMPAD3: if (ViewFile) { /* $ 15.08.2002 IS Для обычного режима, если последняя строка не содержит перевод строки, крутанем вверх на один раз больше - иначе визуально обработка End (и подобных) на такой строке отличается от обработки Down. */ unsigned int max_counter=Y2-Y1; if (VM.Hex) vseek(ViewFile,0,SEEK_END); else { vseek(ViewFile,-1,SEEK_END); WCHAR LastSym=0; if (vgetc(ViewFile,LastSym) && LastSym!=CRSym) ++max_counter; } FilePos=vtell(ViewFile); /* { char Buf[100]; sprintf(Buf,"%I64X",FilePos); Message(0,1,"End",Buf,"Ok"); } */ for (int i=0; static_cast(i)=L' ' && Key<0x10000) { Search(0,Key); return(TRUE); } } return(FALSE); } int Viewer::ProcessMouse(MOUSE_EVENT_RECORD *MouseEvent) { if ((MouseEvent->dwButtonState & 3)==0) return(FALSE); /* $ 22.01.2001 IS Происходят какие-то манипуляции -> снимем выделение */ // SelectSize=0; /* $ 10.09.2000 SVS ! Постоянный скроллинг при нажатой клавише Обыкновенный захват мыши */ /* $ 02.10.2000 SVS > Если нажать в самом низу скролбара, вьюер отмотается на страницу > ниже нижней границы текста. Перед глазами будет пустой экран. */ if (ViOpt.ShowScrollbar && MouseX==X2+(m_bQuickView?1:0)) { /* $ 01.09.2000 SVS Небольшая бага с тыканием в верхнюю позицию ScrollBar`а */ if (MouseY == Y1) while (IsMouseButtonPressed()) ProcessKey(KEY_UP); else if (MouseY==Y2) { while (IsMouseButtonPressed()) { // _SVS(SysLog(L"Viewer/ KEY_DOWN= %i, %i",FilePos,FileSize)); ProcessKey(KEY_DOWN); } } else if (MouseY == Y1+1) ProcessKey(KEY_CTRLHOME); else if (MouseY == Y2-1) ProcessKey(KEY_CTRLEND); else { while (IsMouseButtonPressed()) { /* $ 14.05.2001 DJ более точное позиционирование; корректная работа на больших файлах */ FilePos=(FileSize-1)/(Y2-Y1-1)*(MouseY-Y1); int Perc; if (FilePos > FileSize) { FilePos=FileSize; Perc=100; } else if (FilePos < 0) { FilePos=0; Perc=0; } else Perc=ToPercent64(FilePos,FileSize); //_SVS(SysLog(L"Viewer/ ToPercent()=%i, %I64d, %I64d, Mouse=[%d:%d]",Perc,FilePos,FileSize,MsX,MsY)); if (Perc == 100) ProcessKey(KEY_CTRLEND); else if (!Perc) ProcessKey(KEY_CTRLHOME); else { /* $ 27.04.2001 DJ не рвем строки посередине */ AdjustFilePos(); Show(); } } } return (TRUE); } /* $ 16.12.2000 tran шелчок мышью на статус баре */ /* $ 12.10.2001 SKV угу, а только если он нсть, statusline... */ if (MouseY == (Y1-1) && (HostFileViewer && HostFileViewer->IsTitleBarVisible())) // Status line { int XCodePage, XPos, NameLength; NameLength=ObjWidth-40; if (Opt.ViewerEditorClock && HostFileViewer!=NULL && HostFileViewer->IsFullScreen()) NameLength-=6; if (NameLength<20) NameLength=20; XCodePage=NameLength+1; XPos=NameLength+1+10+1+10+1; while (IsMouseButtonPressed()); if (MouseY != Y1-1) return(TRUE); //_D(SysLog(L"MsX=%i, XTable=%i, XPos=%i",MsX,XTable,XPos)); if (MouseX>=XCodePage && MouseX<=XCodePage+10) { ProcessKey(KEY_SHIFTF8); return (TRUE); } if (MouseX>=XPos && MouseX<=XPos+7+1+4+1+3) { ProcessKey(KEY_ALTF8); return (TRUE); } } if (MouseXX2 || MouseYY2) return(FALSE); if (MouseXX2-7) while (IsMouseButtonPressed() && MouseX>X2-7) ProcessKey(KEY_RIGHT); else if (MouseY=Y1+(Y2-Y1)/2) ProcessKey(KEY_DOWN); return(TRUE); } void Viewer::Up() { if (!ViewFile) return; wchar_t Buf[MAX_VIEWLINE]; int BufSize,StrPos,Skipped,I,J; if (FilePos > (__int64)sizeof(Buf)/sizeof(wchar_t)) BufSize=sizeof(Buf)/sizeof(wchar_t); else BufSize=(int)FilePos; if (BufSize==0) return; LastPage=0; if (VM.Hex) { int UpSize=IsUnicodeCodePage(VM.CodePage) ? 8:16; if (FilePos<(__int64)UpSize) FilePos=0; else FilePos-=UpSize; return; } vseek(ViewFile,FilePos-(__int64)BufSize,SEEK_SET); BufSize = vread(Buf,BufSize,ViewFile); Skipped=0; if (Buf[BufSize-1]==(unsigned int)CRSym) { BufSize--; Skipped++; } if (BufSize>0 && CRSym==L'\n' && Buf[BufSize-1]==L'\r') { BufSize--; Skipped++; } for (I=BufSize-1; I>=-1; I--) { /* $ 29.11.2001 DJ не обращаемся за границу массива (а надо было всего лишь поменять местами условия...) */ if (I==-1 || Buf[I]==(unsigned int)CRSym) { if (!VM.Wrap) { FilePos -= GetStrBytesNum(Buf + (I+1), BufSize-(I+1)) + Skipped; return; } else { if (!Skipped && I==-1) break; for (StrPos=0,J=I+1; J<=BufSize; J++) { if (StrPos==0 || StrPos >= Width) { if (J==BufSize) { if (Skipped==0) FilePos--; else FilePos-=Skipped; return; } if (CalcStrSize(&Buf[J],BufSize-J) <= Width) { FilePos -= GetStrBytesNum(Buf + J, BufSize-J) + Skipped; return; } else StrPos=0; } if (J0; I-=5) if (CalcStrSize(&Buf[BufSize-I],I) <= Width) { FilePos-=I+Skipped; break; } } int Viewer::CalcStrSize(const wchar_t *Str,int Length) { int Size,I; for (Size=0,I=0; IChange( MSG( (!VM.Wrap)?((!VM.WordWrap)?MViewF2:MViewShiftF2) :MViewF2Unwrap),1); ViewKeyBar->Change(KBL_SHIFT,MSG((VM.WordWrap)?MViewF2:MViewShiftF2),1); if (VM.Hex) ViewKeyBar->Change(MSG(MViewF4Text),3); else ViewKeyBar->Change(MSG(MViewF4),3); if (VM.CodePage != GetOEMCP()) ViewKeyBar->Change(MSG(MViewF8DOS),7); else ViewKeyBar->Change(MSG(MViewF8),7); ViewKeyBar->Redraw(); } ViewerMode vm=VM; CtrlObject->Plugins.CurViewer=this; //HostFileViewer; // CtrlObject->Plugins.ProcessViewerEvent(VE_MODE,&vm); } enum SEARCHDLG { SD_DOUBLEBOX, SD_TEXT_SEARCH, SD_EDIT_TEXT, SD_EDIT_HEX, SD_SEPARATOR1, SD_RADIO_TEXT, SD_RADIO_HEX, SD_CHECKBOX_CASE, SD_CHECKBOX_WORDS, SD_CHECKBOX_REVERSE, SD_CHECKBOX_REGEXP, SD_SEPARATOR2, SD_BUTTON_OK, SD_BUTTON_CANCEL, DM_SDSETVISIBILITY = DM_USER + 1, }; LONG_PTR WINAPI ViewerSearchDlgProc(HANDLE hDlg,int Msg,int Param1,LONG_PTR Param2) { switch (Msg) { case DN_INITDIALOG: { SendDlgMessage(hDlg,DM_SDSETVISIBILITY,SendDlgMessage(hDlg,DM_GETCHECK,SD_RADIO_HEX,0) == BSTATE_CHECKED,0); SendDlgMessage(hDlg,DM_EDITUNCHANGEDFLAG,SD_EDIT_TEXT,1); SendDlgMessage(hDlg,DM_EDITUNCHANGEDFLAG,SD_EDIT_HEX,1); return TRUE; } case DM_SDSETVISIBILITY: { SendDlgMessage(hDlg,DM_SHOWITEM,SD_EDIT_TEXT,!Param1); SendDlgMessage(hDlg,DM_SHOWITEM,SD_EDIT_HEX,Param1); SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_CASE,!Param1); SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_WORDS,!Param1); //SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_REGEXP,!Param1); return TRUE; } case DN_BTNCLICK: { if ((Param1 == SD_RADIO_TEXT || Param1 == SD_RADIO_HEX) && Param2) { SendDlgMessage(hDlg,DM_ENABLEREDRAW,FALSE,0); bool Hex=(Param1==SD_RADIO_HEX); string strDataStr; Transform(strDataStr,(const wchar_t *)SendDlgMessage(hDlg,DM_GETCONSTTEXTPTR,Hex?SD_EDIT_TEXT:SD_EDIT_HEX,0),Hex?L'X':L'S'); SendDlgMessage(hDlg,DM_SETTEXTPTR,Hex?SD_EDIT_HEX:SD_EDIT_TEXT,(LONG_PTR)strDataStr.CPtr()); SendDlgMessage(hDlg,DM_SDSETVISIBILITY,Hex,0); if (!strDataStr.IsEmpty()) { SendDlgMessage(hDlg,DM_EDITUNCHANGEDFLAG,Hex?SD_EDIT_HEX:SD_EDIT_TEXT,SendDlgMessage(hDlg,DM_EDITUNCHANGEDFLAG,Hex?SD_EDIT_TEXT:SD_EDIT_HEX,-1)); } SendDlgMessage(hDlg,DM_ENABLEREDRAW,TRUE,0); return TRUE; } } case DN_HOTKEY: { if (Param1==SD_TEXT_SEARCH) { SendDlgMessage(hDlg,DM_SETFOCUS,(SendDlgMessage(hDlg,DM_GETCHECK,SD_RADIO_HEX,0) == BSTATE_CHECKED)?SD_EDIT_HEX:SD_EDIT_TEXT,0); return FALSE; } } } return DefDlgProc(hDlg,Msg,Param1,Param2); } static void PR_ViewerSearchMsg() { PreRedrawItem preRedrawItem=PreRedraw.Peek(); ViewerSearchMsg((const wchar_t*)preRedrawItem.Param.Param1,(int)(INT_PTR)preRedrawItem.Param.Param2); } void ViewerSearchMsg(const wchar_t *MsgStr,int Percent) { string strProgress; if (Percent>=0) { FormatString strPercent; strPercent<(MAX_WIDTH_MESSAGE-2),StrLength(MsgStr)),40)-PercentLength-2; wchar_t *Progress=strProgress.GetBuffer(Length); if (Progress) { size_t CurPos=(Percent>100?100:Percent)*Length/100; wmemset(Progress,BoxSymbols[BS_X_DB],CurPos); wmemset(Progress+(CurPos),BoxSymbols[BS_X_B0],Length-CurPos); strProgress.ReleaseBuffer(Length); FormatString strTmp; strTmp< static_cast(ObjWidth)) TruncStrFromEnd(strMsgStr, ObjWidth-18); InsertQuote(strMsgStr); if (SearchHex) { Transform(strSearchStr,strSearchStr,L'S'); SearchLength=(int)strSearchStr.GetLength(); WholeWords=0; } if (!Case && !SearchHex) strSearchStr.Upper(); SelectSize = 0; if (Next) { if (Next == 2) { SearchFlags.Set(SEARCH_MODE2); LastSelPos = ReverseSearch?FileSize:0; } else LastSelPos = SelectPos + (ReverseSearch?-1:1); } else { LastSelPos = FilePos; if (LastSelPos == 0 || LastSelPos == FileSize) SearchFlags.Set(SEARCH_MODE2); } vseek(ViewFile,LastSelPos,SEEK_SET); Match=0; if (SearchLength>0 && (!ReverseSearch || LastSelPos>0)) { wchar_t Buf[8192]; __int64 CurPos=LastSelPos; int BufSize=countof(Buf); if (ReverseSearch) { /* $ 01.08.2000 KM Изменёно вычисление CurPos с учётом Whole words */ if (WholeWords) CurPos-=countof(Buf)-SearchLength+1; else CurPos-=countof(Buf)-SearchLength; if (CurPos<0) BufSize+=(int)CurPos; } int ReadSize; TaskBar TB; INT64 StartPos=vtell(ViewFile); DWORD StartTime=GetTickCount(); while (!Match) { /* $ 01.08.2000 KM Изменена строка if (ReverseSearch && CurPos<0) на if (CurPos<0), так как при обычном прямом и LastSelPos=0xFFFFFFFF, поиск заканчивался так и не начавшись. */ if (CurPos<0) CurPos=0; vseek(ViewFile,CurPos,SEEK_SET); if ((ReadSize=vread(Buf,BufSize,ViewFile,SearchHex!=0))<=0) break; DWORD CurTime=GetTickCount(); if (CurTime-StartTime>RedrawTimeout) { StartTime=CurTime; if (CheckForEscSilent()) { if (ConfirmAbortOp()) { Redraw(); return; } } INT64 Total=ReverseSearch?StartPos:FileSize-StartPos; INT64 Current=_abs64(CurPos-StartPos); int Percent=Total>0?static_cast(Current*100/Total):-1; // В случае если файл увеличивается размере, то количество // процентов может быть больше 100. Обрабатываем эту ситуацию. if (Percent>100) { SetFileSize(); Total=FileSize-StartPos; Percent=Total>0?static_cast(Current*100/Total):-1; if (Percent>100) { Percent=100; } } ViewerSearchMsg(strMsgStr,Percent); } /* $ 01.08.2000 KM Сделана сразу проверка на Case sensitive и Hex и если нет, тогда Buf приводится к верхнему регистру */ if (!Case && !SearchHex) CharUpperBuff(Buf,ReadSize); /* $ 01.08.2000 KM Убран кусок текста после приведения поисковой строки и Buf к единому регистру, если поиск не регистрозависимый или не ищется Hex-строка и в связи с этим переработан код поиска */ int MaxSize=ReadSize-SearchLength+1; int Increment=ReverseSearch ? -1:+1; for (int I=ReverseSearch ? MaxSize-1:0; I=0; I+=Increment) { /* $ 01.08.2000 KM Обработка поиска "Whole words" */ int locResultLeft=FALSE; int locResultRight=FALSE; if (WholeWords) { if (I!=0) { if (IsSpace(Buf[I-1]) || IsEol(Buf[I-1]) || (wcschr(Opt.strWordDiv,Buf[I-1])!=NULL)) locResultLeft=TRUE; } else { locResultLeft=TRUE; } if (ReadSize!=BufSize && I+SearchLength>=ReadSize) locResultRight=TRUE; else if (I+SearchLengthScrY) FromTop=0; for (int i=0; i=0) OutStr[OutPos++]=N; else break; } memcpy(SearchStr,OutStr,OutPos); SearchLength=OutPos; }*/ int Viewer::HexToNum(int Hex) { Hex=toupper(Hex); if (Hex>='0' && Hex<='9') return(Hex-'0'); if (Hex>='A' && Hex<='F') return(Hex-'A'+10); return(-1000); } int Viewer::GetWrapMode() { return(VM.Wrap); } void Viewer::SetWrapMode(int Wrap) { Viewer::VM.Wrap=Wrap; } void Viewer::EnableHideCursor(int HideCursor) { Viewer::HideCursor=HideCursor; } int Viewer::GetWrapType() { return(VM.WordWrap); } void Viewer::SetWrapType(int TypeWrap) { Viewer::VM.WordWrap=TypeWrap; } void Viewer::GetFileName(string &strName) { strName = strFullFileName; } void Viewer::ShowConsoleTitle() { string strTitle; strTitle.Format(MSG(MInViewer), PointToName(strFileName)); ConsoleTitle::SetFarTitle(strTitle); } void Viewer::SetTempViewName(const wchar_t *Name, BOOL DeleteFolder) { if (Name && *Name) ConvertNameToFull(Name,strTempViewName); else { strTempViewName.Clear(); DeleteFolder=FALSE; } Viewer::DeleteFolder=DeleteFolder; } void Viewer::SetTitle(const wchar_t *Title) { if (Title==NULL) strTitle.Clear(); else strTitle = Title; } void Viewer::SetFilePos(__int64 Pos) { FilePos=Pos; }; void Viewer::SetPluginData(const wchar_t *PluginData) { Viewer::strPluginData = NullToEmpty(PluginData); } void Viewer::SetNamesList(NamesList *List) { if (List!=NULL) List->MoveData(ViewNamesList); } int Viewer::vread(wchar_t *Buf,int Count,FILE *SrcFile,bool Raw) { if (!SrcFile) return -1; if (IsUnicodeCodePage(VM.CodePage)) { // выделяем столько, сколько нужно! char *TmpBuf=(char *)xf_malloc(Count*2+16); if (!TmpBuf) return -1; int ReadSize=(int)fread(TmpBuf,1,Count*2,SrcFile); TmpBuf[ReadSize]=0; /* $ 20.10.2000 tran обратный порядок байтов */ TmpBuf[ReadSize+1]=0; if (!Raw && VM.CodePage == CP_REVERSEBOM) { for (int i=0; i100)) // за пределы - низя // return; if (Percent>100) return; //if ( Percent<0 ) // Percent=0; Offset=FileSize/100*Percent; if (IsUnicodeCodePage(VM.CodePage)) Offset*=2; while (ToPercent64(Offset,FileSize)100) return; //if ( Percent<0 ) // Percent=0; Offset=FileSize/100*Percent; if (IsUnicodeCodePage(VM.CodePage)) Offset*=2; while (ToPercent64(Offset,FileSize)FilePos) // меньше нуля, if (FilePos<0) не пройдет - FilePos у нас unsigned long FilePos=0; else FilePos=IsUnicodeCodePage(VM.CodePage)? FilePos+Offset*Relative/2 : FilePos+Offset*Relative; } else FilePos=IsUnicodeCodePage(VM.CodePage) ? Offset/2:Offset; if (FilePos>FileSize || FilePos<0) // и куда его несет? FilePos=FileSize; // там все равно ничего нету } // коррекция AdjustFilePos(); // LastSelPos=FilePos; if (!(Flags&VSP_NOREDRAW)) Show(); } void Viewer::AdjustFilePos() { if (!VM.Hex) { wchar_t Buf[4096]; __int64 StartLinePos=-1,GotoLinePos=FilePos-(__int64)sizeof(Buf)/sizeof(wchar_t); if (GotoLinePos<0) GotoLinePos=0; vseek(ViewFile,GotoLinePos,SEEK_SET); int ReadSize=(int)Min((__int64)countof(Buf),(__int64)(FilePos-GotoLinePos)); ReadSize=vread(Buf,ReadSize,ViewFile); for (int I=ReadSize-1; I>=0; I--) if (Buf[I]==(unsigned int)CRSym) { StartLinePos=GotoLinePos+I; break; } vseek(ViewFile,FilePos+1,SEEK_SET); if (VM.Hex) FilePos&=~(IsUnicodeCodePage(VM.CodePage) ? 0x7:0xf); else { if (FilePos!=StartLinePos) Up(); } } } void Viewer::SetFileSize() { if (!ViewFile) return; HANDLE hView=reinterpret_cast(_get_osfhandle(ViewFile->_file)); if (hView!=INVALID_HANDLE_VALUE) { UINT64 uFileSize=0; // BUGBUG, sign apiGetFileSizeEx(hView,uFileSize); FileSize=uFileSize; } /* $ 20.02.2003 IS Везде сравниваем FilePos с FileSize, FilePos для юникодных файлов уменьшается в два раза, поэтому FileSize тоже надо уменьшать */ if (IsUnicodeCodePage(VM.CodePage)) FileSize=(FileSize+(FileSize&1))/2; } void Viewer::GetSelectedParam(__int64 &Pos, __int64 &Length, DWORD &Flags) { Pos=SelectPos; Length=SelectSize; Flags=SelectFlags; } /* $ 19.01.2001 SVS Выделение - в качестве самостоятельной функции. Flags=0x01 - показывать (делать Show()) 0x02 - "обратный поиск" ? */ void Viewer::SelectText(const __int64 &MatchPos,const __int64 &SearchLength, const DWORD Flags) { if (!ViewFile) return; wchar_t Buf[1024]; __int64 StartLinePos=-1,SearchLinePos=MatchPos-sizeof(Buf)/sizeof(wchar_t); if (SearchLinePos<0) SearchLinePos=0; vseek(ViewFile,SearchLinePos,SEEK_SET); int ReadSize=(int)Min((__int64)countof(Buf),(__int64)(MatchPos-SearchLinePos)); ReadSize=vread(Buf,ReadSize,ViewFile); for (int I=ReadSize-1; I>=0; I--) if (Buf[I]==(unsigned int)CRSym) { StartLinePos=SearchLinePos+I; break; } //MessageBeep(0); vseek(ViewFile,MatchPos+1,SEEK_SET); SelectPos=FilePos=MatchPos; SelectSize=SearchLength; SelectFlags=Flags; // LastSelPos=SelectPos+((Flags&0x2) ? -1:1); if (VM.Hex) FilePos&=~(IsUnicodeCodePage(VM.CodePage) ? 0x7:0xf); else { if (SelectPos!=StartLinePos) { Up(); Show(); //update OutStr } /* $ 13.03.2001 IS Если найденное расположено в самой первой строке юникодного файла и файл имеет в начале fffe или feff, то для более правильного выделения, его позицию нужно уменьшить на единицу (из-за того, что пустой символ не показывается) */ SelectPosOffSet=(IsUnicodeOrUtfCodePage(VM.CodePage) && Signature && (MatchPos+SelectSize<=ObjWidth && MatchPos<(__int64)StrLength(Strings[0]->lpData)))?1:0; SelectPos-=SelectPosOffSet; __int64 Length=SelectPos-StartLinePos-1; if (VM.Wrap) Length%=Width+1; //?? if (Length<=Width) LeftPos=0; if (Length-LeftPos>Width || Length(MAX_VIEWLINE-1) || LeftPos<0) LeftPos=0; else if (LeftPos>10) LeftPos-=10; } } if (Flags&1) { AdjustSelPosition = TRUE; Show(); AdjustSelPosition = FALSE; } } int Viewer::ViewerControl(int Command,void *Param) { switch (Command) { case VCTL_GETINFO: { if (Param) { ViewerInfo *Info=(ViewerInfo *)Param; memset(&Info->ViewerID,0,Info->StructSize-sizeof(Info->StructSize)); Info->ViewerID=Viewer::ViewerID; Info->FileName=strFullFileName; Info->WindowSizeX=ObjWidth; Info->WindowSizeY=Y2-Y1+1; Info->FilePos=FilePos; Info->FileSize=FileSize; Info->CurMode=VM; Info->Options=0; if (Opt.ViOpt.SavePos) Info->Options|=VOPT_SAVEFILEPOSITION; if (ViOpt.AutoDetectCodePage) Info->Options|=VOPT_AUTODETECTCODEPAGE; Info->TabSize=ViOpt.TabSize; Info->LeftPos=LeftPos; return(TRUE); } break; } /* Param = ViewerSetPosition сюда же будет записано новое смещение В основном совпадает с переданным */ case VCTL_SETPOSITION: { if (Param) { ViewerSetPosition *vsp=(ViewerSetPosition*)Param; bool isReShow=vsp->StartPos != FilePos; if ((LeftPos=vsp->LeftPos) < 0) LeftPos=0; /* $ 20.01.2003 IS Если кодировка - юникод, то оперируем числами, уменьшенными в 2 раза. Поэтому увеличим StartPos в 2 раза, т.к. функция GoTo принимает смещения в _байтах_. */ GoTo(FALSE, vsp->StartPos*(IsUnicodeCodePage(VM.CodePage)?2:1), vsp->Flags); if (isReShow && !(vsp->Flags&VSP_NOREDRAW)) ScrBuf.Flush(); if (!(vsp->Flags&VSP_NORETNEWPOS)) { vsp->StartPos=FilePos; vsp->LeftPos=LeftPos; } return(TRUE); } break; } // Param=ViewerSelect case VCTL_SELECT: { if (Param) { ViewerSelect *vs=(ViewerSelect *)Param; __int64 SPos=vs->BlockStartPos; int SSize=vs->BlockLen; if (SPos < FileSize) { if (SPos+SSize > FileSize) { SSize=(int)(FileSize-SPos); } SelectText(SPos,SSize,0x1); ScrBuf.Flush(); return(TRUE); } } else { SelectSize = 0; Show(); } break; } /* Функция установки Keybar Labels Param = NULL - восстановить, пред. значение Param = -1 - обновить полосу (перерисовать) Param = KeyBarTitles */ case VCTL_SETKEYBAR: { KeyBarTitles *Kbt=(KeyBarTitles*)Param; if (!Kbt) { // восстановить пред значение! if (HostFileViewer!=NULL) HostFileViewer->InitKeyBar(); } else { if ((LONG_PTR)Param != (LONG_PTR)-1) // не только перерисовать? { for (int i=0; i < 12; i++) { if (Kbt->Titles[i]) ViewKeyBar->Change(KBL_MAIN,Kbt->Titles[i],i); if (Kbt->CtrlTitles[i]) ViewKeyBar->Change(KBL_CTRL,Kbt->CtrlTitles[i],i); if (Kbt->AltTitles[i]) ViewKeyBar->Change(KBL_ALT,Kbt->AltTitles[i],i); if (Kbt->ShiftTitles[i]) ViewKeyBar->Change(KBL_SHIFT,Kbt->ShiftTitles[i],i); if (Kbt->CtrlShiftTitles[i]) ViewKeyBar->Change(KBL_CTRLSHIFT,Kbt->CtrlShiftTitles[i],i); if (Kbt->AltShiftTitles[i]) ViewKeyBar->Change(KBL_ALTSHIFT,Kbt->AltShiftTitles[i],i); if (Kbt->CtrlAltTitles[i]) ViewKeyBar->Change(KBL_CTRLALT,Kbt->CtrlAltTitles[i],i); } } ViewKeyBar->Show(); ScrBuf.Flush(); //????? } return(TRUE); } // Param=0 case VCTL_REDRAW: { ChangeViewKeyBar(); Show(); ScrBuf.Flush(); return(TRUE); } // Param=0 case VCTL_QUIT: { /* $ 28.12.2002 IS Разрешаем выполнение VCTL_QUIT только для вьюера, который не является панелью информации и быстрого просмотра (т.е. фактически панелей на экране не видно) */ if (!FrameManager->IsPanelsActive()) { /* $ 29.09.2002 IS без этого не закрывался вьюер, а просили именно это */ FrameManager->DeleteFrame(HostFileViewer); if (HostFileViewer!=NULL) HostFileViewer->SetExitCode(0); return(TRUE); } } /* Функция установки режимов Param = ViewerSetMode */ case VCTL_SETMODE: { ViewerSetMode *vsmode=(ViewerSetMode *)Param; if (vsmode) { bool isRedraw=vsmode->Flags&VSMFL_REDRAW?true:false; switch (vsmode->Type) { case VSMT_HEX: ProcessHexMode(vsmode->Param.iParam,isRedraw); return TRUE; case VSMT_WRAP: ProcessWrapMode(vsmode->Param.iParam,isRedraw); return TRUE; case VSMT_WORDWRAP: ProcessTypeWrapMode(vsmode->Param.iParam,isRedraw); return TRUE; } } return FALSE; } } return(FALSE); } BOOL Viewer::isTemporary() { return !strTempViewName.IsEmpty(); } int Viewer::ProcessHexMode(int newMode, bool isRedraw) { // BUGBUG // До тех пор, пока не будет реализован адекватный hex-просмотр в UTF8 - будем смотреть в OEM. // Ибо сейчас это не просмотр, а генератор однотипных унылых багрепортов. if (VM.CodePage==CP_UTF8 && newMode) { VM.CodePage=Opt.ViOpt.AnsiCodePageAsDefault?GetACP():GetOEMCP(); } int oldHex=VM.Hex; VM.Hex=newMode&1; if (isRedraw) { ChangeViewKeyBar(); Show(); } // LastSelPos=FilePos; return oldHex; } int Viewer::ProcessWrapMode(int newMode, bool isRedraw) { int oldWrap=VM.Wrap; VM.Wrap=newMode&1; if (VM.Wrap) LeftPos = 0; if (!VM.Wrap && LastPage) Up(); if (isRedraw) { ChangeViewKeyBar(); Show(); } Opt.ViOpt.ViewerIsWrap=VM.Wrap; // LastSelPos=FilePos; return oldWrap; } int Viewer::ProcessTypeWrapMode(int newMode, bool isRedraw) { int oldTypeWrap=VM.WordWrap; VM.WordWrap=newMode&1; if (!VM.Wrap) { VM.Wrap=!VM.Wrap; LeftPos = 0; } if (isRedraw) { ChangeViewKeyBar(); Show(); } Opt.ViOpt.ViewerWrap=VM.WordWrap; //LastSelPos=FilePos; return oldTypeWrap; }