View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0001766 | Far Manager | Viewer | public | 2011-05-12 17:45 | 2011-10-11 11:20 |
Reporter | 2useven10 | Assigned To | 2useven10 | ||
Priority | normal | Severity | feature | Reproducibility | N/A |
Status | closed | Resolution | fixed | ||
Product Version | 3.0 | ||||
Fixed in Version | 3.0 | ||||
Summary | 0001766: Новая версия вьювера | ||||
Description | Предлагаю потестить новую версию вьювера (far3 и far2 1807). Все изменения о которых я помню перечислены тут: http://sharapov-16.narod.ru/far/index.html Собранные версии фар и измененные файлы там тоже есть. Здесь патч пока не выкдадываю, хотелось бы получить feedback... | ||||
Tags | No tags attached. | ||||
Build | 2217 | ||||
|
Изменено (по памяти): 1. добавлен поиск регулярных выражений (построчный в обе стороны) 2. добавлено авто-определение кодовой страницы на Shift-F8 3. в авто-детекте можно задать запрещенные codepage-s (параметр) 4. авто-фокус на строке поиска в диалоге (по параметру) 5. повторный поиск всегда зациклен до места начала поиска или смены направления 6. добавлена возможность изменения максимальной длины строки (параметр) |
|
Вот бы еще курсор поддержать - цены бы не было... |
|
А подробнее... Для чего курсор? Только для показа текущей позиции? Или что-то ещё (например выделение текста) ? Поведение курсора в HexView... Как он должен включаться/выключаться... Ну или просто хороший пример вьювера с курсором. |
|
Ну, естественно, чтобы выделять и брать в clipboard. Все как в редакторе, но без возможности править. В Hex-View тоже курсор+выделение не помешает. Есть плагин Hex Editor но он не поддерживает блочные операции. |
|
Можно сделать... но не сейчас - через пару недель (если будет свободное время). |
|
|
|
выложил патч (изменения из #1755 здесь тоже есть) |
|
Уф... вроде Инц про вьювер, а в патче замес по полной... Надо бы разделить... |
|
Так, лажа. Куда делась супер-пупер фича (когда стоим в конце файла и, если его другой процесс "наполняет", то происходит автоскроллинг) из вьювера? |
|
ну вот и фидбэк ( надеюсь будет ещё :) лажу посмотрю-поправлю. а насчет разделить - кроме NoAutoDetectCP (filestr.cpp) все остальное связано с изменениями вьювера... можно только поделить на части. Но тогда процесс затянется надолго (сужу по #1755). К тому же, все что кроме - изменения в несколько строк. |
|
> лажу посмотрю-поправлю. Ок. > Но тогда процесс затянется надолго (сужу по #1755). необязательно. иногда можно и напоминалку "сделать" :-) |
|
я бы взял сразу... но можно и частями. начнём: http://bugs.farmanager.com/view.php?id=1755 [x] http://bugs.farmanager.com/view.php?id=1772 [x] http://bugs.farmanager.com/view.php?id=1773 [x] http://bugs.farmanager.com/view.php?id=1774 [x] автоскролл в своей версии я поправил, но ошибка есть и в транке. если критично - могу сделать отдельный патч (хотя если честно - не хотелось бы) |
|
так, вроде "предварительные ласки" закончились... че дальше? |
|
чуть доделаю поиск с регулярками - пока просто не знаю что делать с соответствием ^$ и найденным текстом нулевой длинны - пока нет курсора, как это показывать, а в hex... думаю сегодня завтра выложу новый новый вьювер :) |
|
NewViewer.diff (93,452 bytes)
Index: viewer.hpp =================================================================== --- viewer.hpp (revision 6286) +++ viewer.hpp (working copy) @@ -40,22 +40,13 @@ #include "config.hpp" #include "cache.hpp" -/* $ 10.07.2000 tran - ! modified MAXSCRY from 120 to 300 - on win200, with Console height FAR work, but trap on viewer... */ -#define MAXSCRY 300 +#define MAXSCRY 512 // 300 // 120 -/* $ 12.07.2000 SVS - - ��-�� �������� ���� ������ �� 0x800 ������ FAR - �� Alt-F7. �������� MAX_VIEWLINE �� 1024 (0x400) -*/ -#define MAX_VIEWLINE 0x800 // 0x400 -#define MAX_VIEWLINEB 0x80f // 0x40f +#define MAX_VIEWLINE (ViOpt.MaxLineSize+ 0) // 0x800 // 0x400 +#define MAX_VIEWLINEB (ViOpt.MaxLineSize+15) // 0x80f // 0x40f #define VIEWER_UNDO_COUNT 64 -enum {VIEW_UNWRAP=0,VIEW_WRAP=1, VIEW_WORDWRAP=2}; - class FileViewer; class KeyBar; @@ -65,7 +56,7 @@ __int64 nFilePos; __int64 nSelStart; __int64 nSelEnd; - int nbytes; + int linesize; bool bSelection; bool have_eol; }; @@ -76,12 +67,6 @@ __int64 UndoLeft; }; -enum SEARCH_FLAGS -{ - SEARCH_MODE2 = 0x00000001, - REVERSE_SEARCH = 0x00000002 -}; - enum SHOW_MODES { SHOW_RELOAD, @@ -95,9 +80,6 @@ friend class FileViewer; private: - - BitFlags SearchFlags; - struct ViewerOptions ViOpt; bool Signature; @@ -105,7 +87,7 @@ NamesList ViewNamesList; KeyBar *ViewKeyBar; - ViewerString *Strings[MAXSCRY+1]; + ViewerString **Strings; string strFileName; string strFullFileName; @@ -121,6 +103,8 @@ string strLastSearchStr; int LastSearchCase,LastSearchWholeWords,LastSearchReverse,LastSearchHex,LastSearchRegexp; + int LastSearchDirection; + __int64 StartSearchPos; struct ViewerMode VM; @@ -128,13 +112,12 @@ __int64 SecondPos; __int64 LastScrPos; __int64 FileSize; - __int64 LastSelPos; + __int64 LastSelectPos, LastSelectSize; __int64 LeftPos; __int64 LastPage; __int64 SelectPos,SelectSize; DWORD SelectFlags; - __int64 SelectPosOffSet; // ���������� �� �������� ������ ������� � ������� ����� int ShowStatusLine,HideCursor; string strTitle; @@ -165,9 +148,20 @@ char *vread_buffer; int vread_buffer_size; - wchar_t *Up_buffer; - int Up_buffer_size; + __int64 lcache_first; + __int64 lcache_last; + __int64 *lcache_lines; + int lcache_size; + int lcache_count; + int lcache_base; + bool lcache_ready; + int lcache_wrap; + int lcache_wwrap; + int lcache_width; + wchar_t *Search_buffer; + int Search_buffer_size; + ViewerString vString; unsigned char vgetc_buffer[32]; @@ -181,8 +175,9 @@ void ShowPage(int nMode); - void Up(); - int WrappedLength(wchar_t *str, int line_size); + void Up(int n); + void CacheLine(__int64 start, int length, bool have_eol); + int CacheFindUp(__int64 start); void ShowHex(); void ShowStatus(); @@ -195,17 +190,31 @@ void AdjustWidth(); void AdjustFilePos(); - void ReadString(ViewerString *pString, int MaxSize); - int CalcStrSize(const wchar_t *Str,int Length); + void ReadString(ViewerString *pString, int MaxSize, bool update_cache=true); + __int64 EndOfScreen( int line ); + __int64 BegOfScreen(); + void ChangeViewKeyBar(); + void Search(int Next,int FirstChar); - void ConvertToHex(char *SearchStr,int &SearchLength); + // + struct search_data; + // + int search_hex_forward( search_data* sd ); + int search_hex_backward( search_data* sd ); + int search_text_forward( search_data* sd ); + int search_text_backward( search_data* sd ); + int search_regex_forward( search_data* sd ); + int search_regex_backward( search_data* sd ); + int read_line(wchar_t *buf, wchar_t *tbuf, INT64 cpos, int adjust, INT64 &lpos, int &lsize); + int vread(wchar_t *Buf, int Count, wchar_t *Buf2 = nullptr); bool vseek(__int64 Offset, int Whence); __int64 vtell(); bool vgetc(wchar_t *ch); bool veof(); + wchar_t vgetc_prev(); void SetFileSize(); int GetStrBytesNum(const wchar_t *Str, int Length); @@ -283,5 +292,5 @@ int ProcessWrapMode(int newMode, bool isRedraw=TRUE); int ProcessTypeWrapMode(int newMode, bool isRedraw=TRUE); - void SearchTextTransform(UnicodeString &to, const wchar_t *from, bool hex2text); + void SearchTextTransform(UnicodeString &to, const wchar_t *from, bool hex2text, int &pos); }; Index: viewer.cpp =================================================================== --- viewer.cpp (revision 6286) +++ viewer.cpp (working copy) @@ -65,18 +65,20 @@ #include "constitle.hpp" #include "console.hpp" #include "wakeful.hpp" +#include "RegExp.hpp" static void PR_ViewerSearchMsg(); -static void ViewerSearchMsg(const wchar_t *Name,int Percent); +static void ViewerSearchMsg(const wchar_t *name, int percent, int search_hex); -static int InitHex=FALSE,SearchHex=FALSE; +//static int InitHex=FALSE,SearchHex=FALSE; static int ViewerID=0; static int utf8_to_WideChar(const char *s, int nc, wchar_t *w1,wchar_t *w2, int wlen, int &tail); -#define REPLACE_CHAR 0xFFFD // Replacement +#define REPLACE_CHAR 0xFFFD // Replacement #define CONTINUE_CHAR 0x203A // Single Right-Pointing Angle Quotation Mark +#define BOM_CHAR 0xFEFF // Zero Length Space Viewer::Viewer(bool bQuickView, UINT aCodePage): ViOpt(Opt.ViOpt), @@ -85,10 +87,11 @@ { _OT(SysLog(L"[%p] Viewer::Viewer()", this)); - for (int i=0; i<=MAXSCRY; i++) + Strings = new ViewerString*[MAXSCRY+1]; + for (int i=0; i <= MAXSCRY; i++) { Strings[i] = new ViewerString(); - Strings[i]->lpData = new wchar_t[MAX_VIEWLINEB]; + memset(Strings[i], 0, sizeof(ViewerString)); } strLastSearchStr = strGlobalSearchString; @@ -97,19 +100,21 @@ LastSearchWholeWords=GlobalSearchWholeWords; LastSearchReverse=GlobalSearchReverse; LastSearchHex=GlobalSearchHex; + LastSearchDirection = GlobalSearchReverse ? -1 : +1; + StartSearchPos = 0; VM.CodePage=DefCodePage=aCodePage; // �������� ��� ����� VM.Wrap=Opt.ViOpt.ViewerIsWrap; VM.WordWrap=Opt.ViOpt.ViewerWrap; - VM.Hex=InitHex; + VM.Hex = FALSE; //InitHex; ViewKeyBar=nullptr; FilePos=0; LeftPos=0; SecondPos=0; FileSize=0; LastPage=0; - SelectPos=SelectSize=0; - LastSelPos=0; + SelectPos = 0; SelectSize = -1; + LastSelectPos = 0; LastSelectSize = -1; SetStatusMode(TRUE); HideCursor=TRUE; DeleteFolder=TRUE; @@ -123,7 +128,6 @@ CtrlObject->Plugins.CurViewer=this; OpenFailed=false; HostFileViewer=nullptr; - SelectPosOffSet=0; bVE_READ_Sent = false; Signature = false; @@ -132,8 +136,17 @@ vgetc_composite = L'\0'; vread_buffer = new char[vread_buffer_size = 8192]; - Up_buffer = new wchar_t[Up_buffer_size = 2 * (3*MAX_VIEWLINE + 2)]; + lcache_first = lcache_last = -1; + lcache_lines = new INT64[lcache_size = 8*1000]; + lcache_count = 0; + lcache_base = 0; + lcache_ready = false; + lcache_wrap = lcache_wwrap = lcache_width = -1; + + Search_buffer_size = 3 * (MAX_VIEWLINEB < 8000 ? 8000 : MAX_VIEWLINEB); + Search_buffer = new wchar_t[Search_buffer_size]; + memset(&vString, 0, sizeof(vString)); vString.lpData = new wchar_t[MAX_VIEWLINEB]; } @@ -169,7 +182,8 @@ } delete[] vString.lpData; - delete[] Up_buffer; + delete[] Search_buffer; + delete[] lcache_lines; delete[] vread_buffer; _tran(SysLog(L"[%p] Viewer::~Viewer, TempViewName=[%s]",this,TempViewName)); @@ -192,11 +206,13 @@ } } - for (int i=0; i<=MAXSCRY; i++) + for (int i=MAXSCRY; i >= 0; --i) { - delete [] Strings[i]->lpData; + if (Strings[i]->lpData) + delete[] Strings[i]->lpData; delete Strings[i]; } + delete[] Strings; if (!OpenFailed && bVE_READ_Sent) { @@ -216,7 +232,7 @@ Opt.ViOpt.ViewerIsWrap=VM.Wrap; Opt.ViOpt.ViewerWrap=VM.WordWrap; Opt.ViOpt.SearchRegexp=LastSearchRegexp; - InitHex=VM.Hex; + //InitHex=VM.Hex; } @@ -229,7 +245,7 @@ ViewFile.Close(); Reader.Clear(); - SelectSize = 0; // ������� �������� + SelectSize = -1; // ������� �������� strFileName = Name; if (Opt.OnlyEditorViewerUsed && !StrCmp(strFileName, L"-")) @@ -302,7 +318,7 @@ // �������� ������������� ��� ��� ���������� �� �� ������ ������� if (CachedCodePage && !IsCodePageSupported(CachedCodePage)) CachedCodePage = 0; - LastSelPos=FilePos=NewFilePos; + LastSelectPos=FilePos=NewFilePos; LeftPos=NewLeftPos; } else @@ -350,19 +366,13 @@ CodePageChangedByUser=TRUE; } - if (!IsUnicodeOrUtfCodePage(VM.CodePage)) - { - ViewFile.SetPointer(0, nullptr, FILE_BEGIN); - } + ViewFile.SetPointer(0, nullptr, FILE_BEGIN); } SetFileSize(); - if (FilePos>FileSize) + if (FilePos > FileSize) FilePos=0; -// if (ViOpt.AutoDetectTable && !TableChangedByUser) -// { -// } ChangeViewKeyBar(); AdjustWidth(); CtrlObject->Plugins.CurViewer=this; // HostFileViewer; @@ -379,12 +389,12 @@ DriveType = DRIVE_CDROM; switch (DriveType) //??? make it configurable { - case DRIVE_REMOVABLE: update_check_period = -1; break; // flash drive or floppy: never - case DRIVE_FIXED: update_check_period = +1; break; // hard disk: 1msec - case DRIVE_REMOTE: update_check_period = 1000; break; // network drive: 1sec - case DRIVE_CDROM: update_check_period = -1; break; // cd/dvd: never - case DRIVE_RAMDISK: update_check_period = +1; break; // ramdrive: 1msec - default: update_check_period = -1; break; // unknown: never + case DRIVE_REMOVABLE: update_check_period = -1; break; // flash drive or floppy: never + case DRIVE_FIXED: update_check_period = +1; break; // hard disk: 1 msec + case DRIVE_REMOTE: update_check_period = 500; break; // network drive: 0.5 sec + case DRIVE_CDROM: update_check_period = -1; break; // cd/dvd: never + case DRIVE_RAMDISK: update_check_period = +1; break; // ramdrive: 1 msec + default: update_check_period = -1; break; // unknown: never } return TRUE; @@ -428,8 +438,9 @@ SetCursorType(0,10); vseek(FilePos,SEEK_SET); + LastPage = 0; - if (!SelectSize) + if ( SelectSize < 0 ) SelectPos=FilePos; switch (nMode) @@ -471,7 +482,7 @@ } FilePos = Strings[0]->nFilePos; SecondPos = Strings[1]->nFilePos; - Strings[Y2-Y1]->nFilePos = Strings[Y2-Y1-1]->nFilePos + Strings[Y2-Y1-1]->nbytes; + Strings[Y2-Y1]->nFilePos = Strings[Y2-Y1-1]->nFilePos + Strings[Y2-Y1-1]->linesize; vseek(Strings[Y2-Y1]->nFilePos, SEEK_SET); ReadString(Strings[Y2-Y1],-1); break; @@ -487,21 +498,14 @@ if (StrLen > LeftPos) { - if (IsUnicodeOrUtfCodePage(VM.CodePage) && Signature && !I && !Strings[I]->nFilePos) - { - FS<<fmt::LeftAlign()<<fmt::Width(Width)<<fmt::Precision(Width)<<&Strings[I]->lpData[static_cast<size_t>(LeftPos+1)]; - } - else - { - FS<<fmt::LeftAlign()<<fmt::Width(Width)<<fmt::Precision(Width)<<&Strings[I]->lpData[static_cast<size_t>(LeftPos)]; - } + FS<<fmt::LeftAlign()<<fmt::Width(Width)<<fmt::Precision(Width)<<&Strings[I]->lpData[static_cast<size_t>(LeftPos)]; } else { FS<<fmt::Width(Width)<<L""; } - if (SelectSize && Strings[I]->bSelection) + if ( SelectSize >= 0 && Strings[I]->bSelection) { __int64 SelX1; @@ -532,7 +536,7 @@ if (LeftPos > Strings[I]->nSelEnd) Length = 0; - FS<<fmt::Precision(static_cast<int>(Length))<<&Strings[I]->lpData[static_cast<size_t>(SelX1+LeftPos+SelectPosOffSet)]; + FS<<fmt::Precision(static_cast<int>(Length))<<&Strings[I]->lpData[static_cast<size_t>(SelX1+LeftPos)]; } } @@ -571,6 +575,9 @@ bool bSelStartFound = false, bSelEndFound = false; __int64 HexLeftPos=((LeftPos>80-ObjWidth) ? Max(80-ObjWidth,0):LeftPos); + const wchar_t BorderLine[] = {BoxSymbols[BS_V1],L' ',0}; + int border_len = (int)wcslen(BorderLine); + for (EndFile=0,Y=Y1; Y<=Y2; Y++) { bSelStartFound = false; @@ -588,12 +595,9 @@ if (Y==Y1+1 && !veof()) SecondPos=vtell(); - INT64 Ptr=ViewFile.GetPointer(); - _snwprintf(OutStr,ARRAYSIZE(OutStr),L"%010I64X: ", Ptr); + int out_len = _snwprintf(OutStr,ARRAYSIZE(OutStr),L"%010I64X: ", vtell()); + SelEnd = SelStart = out_len; TextPos=0; - int HexStrStart = (int)wcslen(OutStr); - SelStart = HexStrStart; - SelEnd = SelStart; __int64 fpos = vtell(); if (fpos > SelectPos) @@ -602,103 +606,108 @@ if (fpos < SelectPos+SelectSize-1) bSelEndFound = true; - if (!SelectSize) + if ( SelectSize < 0 ) bSelStartFound = bSelEndFound = false; - const wchar_t BorderLine[]={BoxSymbols[BS_V1],L' ',0}; + unsigned char line[16+3]; + DWORD nr = 0; + DWORD nb = CP_UTF8 == VM.CodePage ? 16+3 : 16; + Reader.Read(line, nb, &nr); + if (nr > 16) + Reader.Unread(nr-16); - int out_len = (int)wcslen(OutStr); - int border_len = (int)wcslen(BorderLine); + LastPage = EndFile = (nr <= nb) && veof() ? 1 : 0; - if (IsUnicodeCodePage(VM.CodePage)) + if (nr <= 0) { - wchar_t line[8]; - int nr = vread(line, 8); - LastPage = EndFile = veof() ? 1 : 0; - if (nr <= 0) + *OutStr = L'\0'; + } + else + { + if (IsUnicodeCodePage(VM.CodePage)) { - *OutStr = L'\0'; - } - else - { - for (X=0; X<8; X++) + int be = VM.CodePage == CP_REVERSEBOM ? 1 : 0; + for (X=0; X<16; X += 2) { - if (SelectSize>0 && (SelectPos == fpos)) + if (SelectSize >= 0 && (SelectPos == fpos || SelectPos == fpos+1)) { + bool half = SelectPos != fpos; bSelStartFound = true; - SelStart = (int)wcslen(OutStr); - SelSize=SelectSize; + SelStart = out_len + (half ? 1+be : 0); + if ( 0 == (SelSize=SelectSize) ) + SelStart += (half ? be : 0) - 1; } - if (SelectSize>0 && (fpos == (SelectPos+SelectSize-1))) + if (SelectSize >= 0 && (fpos == SelectPos+SelectSize-1 || fpos+1 == SelectPos+SelectSize-1)) { + bool half = fpos == SelectPos+SelectSize-1; bSelEndFound = true; - SelEnd = (int)wcslen(OutStr)+3; - SelSize=SelectSize; + SelEnd = out_len+3 - (half ? 1+be : 0); + if ( 0 == (SelSize=SelectSize) ) + SelEnd = SelStart; } + else if ( SelectSize == 0 && (SelectPos == fpos || SelectPos == fpos+1) ) + { + bSelEndFound = true; + SelSize = 0; + SelEnd = SelStart; + } - if (X < nr) + if ((DWORD)X < nr-1) // full character { - unsigned char b1 = HIBYTE(line[X]), b2 = LOBYTE(line[X]); -#if 0 // !!! ��������� �������� !!! - if (VM.CodePage != CP_REVERSEBOM) // ��� ������ � ���� ���� - { // ������� �������� ������������� ��� - unsigned char t = b1; b1 = b2; b2 = t; - } -#endif - _snwprintf(OutStr+out_len, ARRAYSIZE(OutStr)-out_len, L"%02X%02X ", b1, b2); - TextStr[TextPos++] = line[X] ? line[X] : L' '; + unsigned ch = line[X+be] + (line[X+1-be] << 8); + _snwprintf(OutStr+out_len, ARRAYSIZE(OutStr)-out_len, L"%04X ", ch); + TextStr[TextPos++] = ch ? (wchar_t)ch : L' '; } - else + else if ((DWORD)X == nr-1) // half character only { + int o1 = 2 * (1 - be); + _snwprintf(OutStr+out_len+o1, ARRAYSIZE(OutStr)-out_len-o1, L"%02X", line[X]); + OutStr[out_len+2-o1] = OutStr[out_len+2-o1+1] = L'x'; + OutStr[out_len+4] = L' '; + TextStr[TextPos++] = REPLACE_CHAR; + } + else // no character + { wcscpy(OutStr+out_len, L" "); TextStr[TextPos++] = L' '; } out_len += 5; - if (X == 3) + if (X == 3*2) { wcscpy(OutStr+out_len, BorderLine); out_len += border_len; } - ++fpos; + fpos += 2; } } - } - else - { - unsigned char line[16+3]; - DWORD nr = 0; - DWORD nb = CP_UTF8 == VM.CodePage ? 16+3 : 16; - Reader.Read(line, nb, &nr); - if (nr > 16) - Reader.Unread(nr-16); - - LastPage = EndFile = (nr <= nb) && veof() ? 1 : 0; - - if (!nr) - { - *OutStr = L'\0'; - } else { - if (SelectSize) + if ( SelectSize >= 0 ) { if (SelectPos >= fpos && SelectPos < fpos+16) { int off = (int)(SelectPos - fpos); bSelStartFound = true; SelStart = out_len + 3*off + (off < 8 ? 0 : border_len); - SelSize = SelectSize; + if ( 0 == (SelSize=SelectSize) ) + --SelStart; } __int64 selectEnd = SelectPos + SelectSize - 1; if (selectEnd >= fpos && selectEnd < fpos+16) { int off = (int)(selectEnd - fpos); bSelEndFound = true; - SelEnd = out_len + 3*off + (off < 8 ? 0 : border_len) + 1; - SelSize = SelectSize; + SelEnd = (0 == (SelSize=SelectSize) ? SelStart : out_len + 3*off + (off < 8 ? 0 : border_len) + 1); } + else if ( SelectSize == 0 && SelectPos == fpos ) + { + bSelEndFound = true; + SelSize = 0; + SelEnd = SelStart; + } } + for (X=0; X<16; X++) { int off = out_len + 3*X + (X < 8 ? 0 : border_len); @@ -712,6 +721,7 @@ if (CP_UTF8 != VM.CodePage && X < (int)nr && line[X]) MultiByteToWideChar(VM.CodePage, 0, (LPCSTR)line+X, 1, TextStr+X, 1); } + out_len += 3*16 + border_len; if (CP_UTF8 == VM.CodePage) { @@ -730,7 +740,7 @@ first = false; TextStr[ib++] = w1[iw] ? w1[iw] : L' '; } - int clen = WideCharToMultiByte(CP_UTF8, 0, w2+iw, 1, nullptr, 0, nullptr, nullptr); + int clen = WideCharToMultiByte(CP_UTF8, 0, w2+iw, 1, NULL,0, NULL,NULL); while (--clen > 0 && ib < 16) TextStr[ib++] = CONTINUE_CHAR; ++iw; @@ -740,14 +750,14 @@ } } - TextStr[TextPos]=0; - wcscat(TextStr,L" "); + TextStr[TextPos] = L' '; + TextStr[TextPos+1] = L'\0'; - if ((SelEnd <= SelStart) && bSelStartFound) - SelEnd = (int)wcslen(OutStr)-2; + if ((SelEnd <= SelStart) && bSelStartFound && bSelEndFound && SelectSize > 0 ) + SelEnd = out_len-2; - wcscat(OutStr,L" "); - wcscat(OutStr,TextStr); + OutStr[out_len] = L' '; + wcscpy(OutStr+out_len+1, TextStr); if (StrLength(OutStr)>HexLeftPos) { @@ -789,7 +799,7 @@ { 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); + ScrollBarEx(X2+(m_bQuickView?1:0),Y1,Y2-Y1+1,LastPage?Top?Total:0:Top,Total); } } } @@ -837,6 +847,15 @@ return L'\0' == ch || IsSpace(ch); } +static bool is_word_div ( const wchar_t ch ) +{ + static const wchar_t spaces[] = { L' ', L'\t', L'\n', L'\r', BOM_CHAR, REPLACE_CHAR, L'\0' }; + return ( !ch + || nullptr != wcschr(spaces, ch) + || nullptr != wcschr(Opt.strWordDiv, ch) + ); +} + static inline int wrapped_char( const wchar_t ch ) { static const wchar_t wrapped_chars[] = L",;>)"; // word-wrap enabled after it @@ -849,18 +868,31 @@ return -1; } -void Viewer::ReadString(ViewerString *pString, int MaxSize) +static inline int getCharSize( UINT cp ) { + if ( CP_UTF8 == cp ) + return -1; + else if ( CP_UNICODE == cp || CP_REVERSEBOM == cp ) + return +2; + else + return +1; +} + +void Viewer::ReadString( ViewerString *pString, int MaxSize, bool update_cache ) +{ AdjustWidth(); int OutPtr = 0, nTab = 0, wrap_out = -1; wchar_t ch, eol_char = L'\0'; - __int64 fpos, sel_end, wrap_pos = -1; + INT64 fpos=0, fpos1, sel_end, wrap_pos = -1; bool skip_space = false; + if ( !pString->lpData ) + pString->lpData = new wchar_t[MAX_VIEWLINEB]; + if (VM.Hex) { - vseek(IsUnicodeCodePage(VM.CodePage) ? 8 : 16, FILE_CURRENT); + vseek(16, FILE_CURRENT); pString->lpData[OutPtr] = L'\0'; LastPage = veof(); return; @@ -869,10 +901,12 @@ bool bSelStartFound = false, bSelEndFound = false; pString->bSelection = false; sel_end = SelectPos + SelectSize; - fpos = vtell(); + fpos1 = vtell(); for (;;) { + fpos = fpos1; + if (OutPtr >= MAX_VIEWLINE) break; @@ -880,27 +914,31 @@ ch = L' '; else { - fpos = vtell(); if (!MaxSize-- || !vgetc(&ch)) break; } + fpos1 = vtell(); - if (SelectSize > 0) + if (SelectSize >= 0) { - if (fpos == SelectPos) + if (fpos == SelectPos || (fpos < SelectPos && fpos1 > SelectPos)) { pString->nSelStart = OutPtr; bSelStartFound = true; } - if (fpos == sel_end) + if (fpos == sel_end || (fpos < sel_end && fpos1 > sel_end)) { - pString->nSelEnd = OutPtr; + pString->nSelEnd = OutPtr + (fpos < sel_end ? 1 : 0); bSelEndFound = true; } } - if (L'\t' == ch) + if (!fpos && BOM_CHAR == ch) { + continue; // skip BOM + } + else if (L'\t' == ch) + { nTab = ViOpt.TabSize - (OutPtr % ViOpt.TabSize); continue; } @@ -913,7 +951,7 @@ pString->lpData[OutPtr++] = ch ? ch : L' '; if (!VM.Wrap) continue; - + if (OutPtr >= Width) { if (VM.WordWrap && wrap_out > 0) @@ -965,9 +1003,12 @@ pString->have_eol = (eol_char != L'\0'); pString->lpData[(int)OutPtr]=0; - pString->nbytes = (int)(vtell() - pString->nFilePos); + pString->linesize = (int)(vtell() - pString->nFilePos); - if (SelectSize > 0 && OutPtr > 0) + if ( update_cache ) + CacheLine(pString->nFilePos, pString->linesize, pString->have_eol); + + if (SelectSize >= 0 && OutPtr > 0) { if (!bSelStartFound && pString->nFilePos >= SelectPos && pString->nFilePos <= sel_end) { @@ -987,8 +1028,86 @@ if (!eol_char && veof()) LastPage = 1; +} + + +__int64 Viewer::EndOfScreen( int line ) +{ + __int64 pos; + + if (!VM.Hex) + { + pos = Strings[Y2-Y1+line]->nFilePos + Strings[Y2-Y1+line]->linesize; + if ( !line && !VM.Wrap && Strings[Y2-Y1]->linesize > 0 ) + { + vseek(Strings[Y1-Y2]->nFilePos, SEEK_SET); + int col = 0, rmargin = (int)LeftPos + Width; + wchar_t ch; + for (;;) + { + if ( !vgetc(&ch) ) + break; + if ( ch == L'\n' || ch == L'\r' ) + break; + if ( ch == L'\t' ) + col += ViOpt.TabSize - (col % ViOpt.TabSize); + else + ++col; + if ( col >= rmargin ) + { + pos = vtell(); + break; + } + } + } + } + else + pos = FilePos + 16 * (Y2-Y1+1+line); + + if (pos < 0) + pos = 0; + else if (pos > FileSize) + pos = FileSize; + + return pos; } + +__int64 Viewer::BegOfScreen() +{ + __int64 pos = FilePos, prev_pos; + + if (!VM.Hex && !VM.Wrap && LeftPos > 0) + { + vseek(FilePos, SEEK_SET); + int col = 0; + wchar_t ch; + pos = -1; + for (;;) + { + prev_pos = vtell(); + if ( !vgetc(&ch) ) + break; + if ( ch == L'\n' || ch == L'\r' ) + { + pos = Strings[1]->nFilePos; + break; + } + if ( ch == L'\t' ) + col += ViOpt.TabSize - (col % ViOpt.TabSize); + else + ++col; + if ( col > LeftPos ) //!! ������ �������� ����� ������ + break; //!! ��� LeftPos=1 �� ���� 2 ������� + } + if ( pos < 0 ) + pos = (col > LeftPos ? prev_pos : vtell()); + } + + return pos; +} + + __int64 Viewer::VMProcess(int OpCode,void *vParam,__int64 iParam) { switch (OpCode) @@ -996,7 +1115,7 @@ case MCODE_C_EMPTY: return (__int64)!FileSize; case MCODE_C_SELECTED: - return (__int64)(SelectSize?TRUE:FALSE); + return (__int64)(SelectSize >= 0 ?TRUE:FALSE); case MCODE_C_EOF: return (__int64)(LastPage || !ViewFile.Opened()); case MCODE_C_BOF: @@ -1030,7 +1149,7 @@ */ if (!ViOpt.PersistentBlocks && Key!=KEY_IDLE && Key!=KEY_NONE && !(Key==KEY_CTRLINS||Key==KEY_CTRLNUMPAD0) && Key!=KEY_CTRLC) - SelectSize=0; + SelectSize = -1; if (!InternalKey && !LastKeyUndo && (FilePos!=UndoData[0].UndoAddr || LeftPos!=UndoData[0].UndoLeft)) { @@ -1055,7 +1174,6 @@ { FilePos=BMSavePos.FilePos[Pos]; LeftPos=BMSavePos.LeftPos[Pos]; -// LastSelPos=FilePos; Show(); } @@ -1082,25 +1200,20 @@ } case KEY_CTRLU: { -// if (SelectSize) - { - SelectSize = 0; - Show(); - } + SelectSize = -1; + Show(); return TRUE; } case KEY_CTRLC: case KEY_CTRLINS: case KEY_CTRLNUMPAD0: { - if (SelectSize && ViewFile.Opened()) + if (SelectSize >= 0 && ViewFile.Opened()) { - wchar_t *SelData; - size_t DataSize = (size_t)SelectSize+(IsUnicodeCodePage(VM.CodePage)?sizeof(wchar_t):1); - __int64 CurFilePos=vtell(); - - if ((SelData=(wchar_t*)xf_malloc(DataSize*sizeof(wchar_t))) ) + wchar_t *SelData = (wchar_t*)xf_malloc((size_t)SelectSize+1); + if ( SelData ) { - wmemset(SelData, 0, DataSize); + __int64 CurFilePos=vtell(); + wmemset(SelData, 0, (size_t)SelectSize+1); vseek(SelectPos,SEEK_SET); vread(SelData, (int)SelectSize); CopyToClipboard(SelData); @@ -1108,7 +1221,6 @@ vseek(CurFilePos,SEEK_SET); } } - return TRUE; } // �����/����� �������� @@ -1145,6 +1257,8 @@ Reader.Clear(); // ���� ���� �� ��� ����? ViewFile.FlushBuffers(); + vseek(0, SEEK_CUR); // reset vgetc state + lcache_ready = false; // reset start-lines cache if (FilePos>FileSize) { @@ -1251,19 +1365,16 @@ } case KEY_SHIFTF2: { - LastPage = 0; ProcessTypeWrapMode(!VM.WordWrap); return TRUE; } case KEY_F2: { - LastPage = 0; ProcessWrapMode(!VM.Wrap); return TRUE; } case KEY_F4: { - LastPage = 0; ProcessHexMode(!VM.Hex); return TRUE; } @@ -1280,23 +1391,13 @@ } case KEY_ALTF7: { - SearchFlags.Set(REVERSE_SEARCH); - Search(1,0); - SearchFlags.Clear(REVERSE_SEARCH); + Search(-1,0); return TRUE; } case KEY_F8: { - LastPage = 0; - if (IsUnicodeCodePage(VM.CodePage)) - { - FilePos*=2; - SetFileSize(); - SelectPos = 0; - SelectSize = 0; - } - VM.CodePage = VM.CodePage==GetOEMCP() ? GetACP() : GetOEMCP(); + lcache_ready = false; ChangeViewKeyBar(); Show(); CodePageChangedByUser=TRUE; @@ -1304,12 +1405,12 @@ } case KEY_SHIFTF8: { - LastPage = 0; UINT nCodePage = SelectCodePage(VM.CodePage, true, true, false, true); + lcache_ready = false; - if (nCodePage!=(UINT)-1) + if (nCodePage != static_cast<UINT>(-1)) { - if (nCodePage == (WORD)(CP_AUTODETECT & 0xffff)) + if (nCodePage == (CP_AUTODETECT & 0xffff)) { __int64 fpos = vtell(); bool detect = GetFileFormat(ViewFile,nCodePage,&Signature,true) && IsCodePageSupported(nCodePage); @@ -1318,20 +1419,6 @@ nCodePage = Opt.ViOpt.AnsiCodePageAsDefault ? GetACP() : GetOEMCP(); } CodePageChangedByUser=TRUE; - - if (IsUnicodeCodePage(VM.CodePage) && !IsUnicodeCodePage(nCodePage)) - { - FilePos*=2; - SelectPos = 0; - SelectSize = 0; - } - else if (!IsUnicodeCodePage(VM.CodePage) && IsUnicodeCodePage(nCodePage)) - { - FilePos=(FilePos+(FilePos&1))/2; //???? - SelectPos = 0; - SelectSize = 0; - } - VM.CodePage=nCodePage; SetFileSize(); ChangeViewKeyBar(); @@ -1402,11 +1489,10 @@ { if (FilePos>0 && ViewFile.Opened()) { - Up(); // LastPage = 0 + Up(1); // LastPage = 0 if (VM.Hex) { - //FilePos&=~(IsUnicodeCodePage(VM.CodePage) ? 0x7:0xf); Show(); } else @@ -1414,7 +1500,7 @@ ShowPage(SHOW_UP); ViewerString *end = Strings[Y2-Y1]; LastPage = end->nFilePos >= FileSize || - (!end->have_eol && end->nFilePos + end->nbytes >= FileSize); + (!end->have_eol && end->nFilePos + end->linesize >= FileSize); } } @@ -1439,9 +1525,7 @@ { if (ViewFile.Opened()) { - for (int i=Y1; i<Y2; i++) - Up(); - + Up(Y2-Y1); Show(); } @@ -1452,25 +1536,25 @@ if (LastPage || !ViewFile.Opened()) return TRUE; - if (VM.Hex) - FilePos += (IsUnicodeCodePage(VM.CodePage) ? 8 : 16) * (Y2-Y1); - else - FilePos = Strings[Y2-Y1]->nFilePos; + FilePos = EndOfScreen(-1); // start of last screen line if (Key == KEY_CTRLDOWN) { - vseek(FilePos, SEEK_SET); + vseek(vString.nFilePos = FilePos, SEEK_SET); for (int i=Y1; i<=Y2; i++) - ReadString(&vString,-1); + { + ReadString(&vString,-1); + vString.nFilePos += vString.linesize; + } if (LastPage) - { - InternalKey++; - ProcessKey(KEY_CTRLPGDN); - InternalKey--; - return TRUE; + { + InternalKey++; + ProcessKey(KEY_CTRLPGDN); + InternalKey--; + return TRUE; + } } - } Show(); return TRUE; @@ -1504,17 +1588,11 @@ { if (VM.Hex) { - FilePos--; - - if (FilePos<0) - FilePos=0; + FilePos = FilePos > 0 ? FilePos-1 : 0; } else { - LeftPos-=20; - - if (LeftPos<0) - LeftPos=0; + LeftPos = LeftPos > 20 ? LeftPos-20 : 0; } Show(); @@ -1528,10 +1606,7 @@ { if (VM.Hex) { - FilePos++; - - if (FilePos >= FileSize) - FilePos=FileSize-1; //?? + FilePos = FilePos < FileSize-1 ? FilePos+1 : FileSize-1; } else if (!VM.Wrap) { @@ -1592,7 +1667,6 @@ if (ViewFile.Opened()) { FilePos=0; - LastPage = 0; Show(); } @@ -1614,32 +1688,33 @@ ��������� End (� ������) �� ����� ������ �������� �� ��������� Down. */ - unsigned int max_counter=Y2-Y1; + int max_counter = Y2 - Y1; if (VM.Hex) { vseek(0,SEEK_END); FilePos = vtell(); - int line_chars = IsUnicodeCodePage(VM.CodePage) ? 8 : 16; - if ((FilePos % line_chars) == 0) - FilePos -= line_chars * (Y2 - Y1 + 1); + if ((FilePos % 16) == 0) + FilePos -= 16 * (Y2 - Y1 + 1); else - FilePos -= (FilePos % line_chars) + line_chars * (Y2 - Y1); + FilePos -= (FilePos % 16) + 16 * (Y2 - Y1); if (FilePos < 0) FilePos = 0; } else { - vseek(-1,SEEK_END); - WCHAR LastSym=0; + int ch_size = getCharSize(VM.CodePage); + wchar_t LastSym = L'\0'; - if (vgetc(&LastSym) && LastSym!=L'\n' && LastSym!=L'\r') + vseek(0, SEEK_END); + FilePos = vtell() - 1; + FilePos -= FilePos % ch_size; + vseek(FilePos, SEEK_SET); + if (vgetc(&LastSym) && LastSym != L'\n' && LastSym != L'\r') ++max_counter; FilePos=vtell(); - - for (int i=0; static_cast<unsigned int>(i)<max_counter; i++) - Up(); + Up(max_counter); } Show(); @@ -1688,7 +1763,7 @@ { while (IsMouseButtonPressed()) { -// _SVS(SysLog(L"Viewer/ KEY_DOWN= %i, %i",FilePos,FileSize)); + //_SVS(SysLog(L"Viewer/ KEY_DOWN= %i, %i",FilePos,FileSize)); ProcessKey(KEY_DOWN); } } @@ -1719,7 +1794,7 @@ else Perc=ToPercent64(FilePos,FileSize); -//_SVS(SysLog(L"Viewer/ ToPercent()=%i, %I64d, %I64d, Mouse=[%d:%d]",Perc,FilePos,FileSize,MsX,MsY)); + //_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) @@ -1796,140 +1871,270 @@ return TRUE; } -void Viewer::Up() + +void Viewer::CacheLine( __int64 start, int length, bool have_eol ) { - if (!ViewFile.Opened()) + assert(start >= 0 && length >= 0); + if (!length) // empty lines beyond EOF return; - LastPage = 0; + if ( lcache_ready + && (lcache_wrap != VM.Wrap || lcache_wwrap != VM.WordWrap || lcache_width != Width) + ){ + lcache_ready = false; + } - if (FilePos <= 0) - return; - - if (VM.Hex) + if (!lcache_ready || start > lcache_last || start+length < lcache_first) { - FilePos -= IsUnicodeCodePage(VM.CodePage) ? 8 : 16; - if (FilePos < 0) - FilePos = 0; - return; - } + lcache_first = start; + lcache_last = start + length; - int Skipped = 0, I = -1, BufSize = MAX_VIEWLINE + 2; - wchar_t *Buf = Up_buffer, *tBuf = Up_buffer, *tBuf2 = nullptr; + lcache_count = 2; + lcache_base = 0; + lcache_lines[0] = (have_eol ? -start : +start); + lcache_lines[1] = start + length; - if (!VM.Hex && VM.CodePage == CP_UTF8) - { - BufSize = Up_buffer_size / 2; // = 3*MAXLINE + 2; - tBuf = tBuf2 = Up_buffer + BufSize; + lcache_wrap = VM.Wrap; lcache_wwrap = VM.WordWrap; lcache_width = Width; + lcache_ready = true; } - - if (FilePos < (__int64)BufSize) - BufSize = (int)FilePos; - - if (BufSize >= 512) // first try to find newline in first 256 bytes + else if (start == lcache_last) { - vseek(FilePos-256, SEEK_SET); - int nr = vread(Buf, 256, tBuf2); - - if (nr > 0 && Buf[nr-1] == L'\n') + int i = (lcache_base + lcache_count - 1) % lcache_size; + lcache_lines[i] = (have_eol ? -start : +start); + i = (i + 1) % lcache_size; + lcache_lines[i] = lcache_last = start + length; + if (lcache_count < lcache_size) + ++lcache_count; + else { - --nr; ++Skipped; + lcache_base = (lcache_base + 1) % lcache_size; // ++start + lcache_first = _abs64(lcache_lines[lcache_base]); } - if (nr > 0 && Buf[nr-1] == L'\r') + } + else if (start+length == lcache_first) + { + lcache_base = (lcache_base + lcache_size - 1) % lcache_size; // --start + lcache_lines[lcache_base] = (have_eol ? -start : +start); + lcache_first = start; + if (lcache_count < lcache_size) + ++lcache_count; + else { - --nr; ++Skipped; + int i = (lcache_base + lcache_size - 1) % lcache_size; // i = start - 1 + lcache_last = _abs64(lcache_lines[i]); } + } + else + { +#if defined(_DEBUG) && 1 // it is legal case if file changed... + assert(start >= lcache_first && start+length <= lcache_last); + int i = CacheFindUp(start+length); + assert(i >= 0 && _abs64(lcache_lines[i]) == start); +#endif + lcache_first = start; + lcache_last = start + length; - for (I = nr-1; I >= 0; I--) - { - if (Buf[I] == L'\n' || Buf[I] == L'\r') - { - BufSize = nr; - break; - } - } + lcache_count = 2; + lcache_base = 0; + lcache_lines[0] = (have_eol ? -start : +start); + lcache_lines[1] = start + length; } +} - if (I < 0) // full portion read +int Viewer::CacheFindUp( __int64 start ) +{ + if ( lcache_ready + && (lcache_wrap != VM.Wrap || lcache_wwrap != VM.WordWrap || lcache_width != Width) + ){ + lcache_ready = false; + } + if ( !lcache_ready || start <= lcache_first || start > lcache_last ) + return -1; + + int i, j, i1 = 0, i2 = lcache_count - 1; + for (;;) { - vseek(FilePos - BufSize, SEEK_SET); - BufSize = vread(Buf, BufSize, tBuf2); - Skipped=0; + if ( i1+1 >= i2 ) + return (lcache_base + i1) % lcache_size; - if (BufSize > 0 && Buf[BufSize-1]==L'\n') - { - --BufSize; ++Skipped; - } - if (BufSize > 0 && Buf[BufSize-1] == L'\r') - { - --BufSize; ++Skipped; - } - - int I0 = BufSize > MAX_VIEWLINE ? BufSize - MAX_VIEWLINE : 0; - for (I = BufSize-1; I >= I0; I--) - { - if (Buf[I] == L'\n' || Buf[I] == L'\r') - break; - } + i = (i1 + i2) / 2; + j = (lcache_base + i) % lcache_size; + if (_abs64(lcache_lines[j]) < start) + i1 = i; + else + i2 = i; } +} - if (!VM.Wrap) +void Viewer::Up( int nlines ) +{ + assert( nlines > 0 ); + + if (!ViewFile.Opened()) + return; + + LastPage = 0; + + if (FilePos <= 0) + return; + + if (VM.Hex) { - FilePos -= GetStrBytesNum(tBuf + (I+1), BufSize-(I+1)) + Skipped; + FilePos = FilePos > 16*nlines ? FilePos-16*nlines : 0; + return; } - else + + __int64 fpos, fpos1; + + int i = CacheFindUp(fpos = FilePos); + if ( i >= 0 ) { - wchar_t *line = tBuf + I+1; - int len, line_size = BufSize - (I+1); for (;;) { - len = WrappedLength(line, line_size); - if ( len >= line_size ) + fpos = _abs64(lcache_lines[i]); + if (--nlines == 0) + { + FilePos = fpos; + return; + } + if (i == lcache_base) break; - line += len; - line_size -= len; + i = (i + lcache_size - 1) % lcache_size; } - FilePos -= GetStrBytesNum(line, line_size + Skipped); } - return; -} -int Viewer::WrappedLength(wchar_t *str, int line_size) -{ - int width = 0, off = 0, wrap_pos = -1, wrap_ch, tab_size = ViOpt.TabSize; - bool wwrap = VM.Wrap && VM.WordWrap; + static const int portion_size = 256; + static const int max_backward = 32*1024; - for (;;) + union { + char c1[portion_size]; + wchar_t c2[portion_size/(int)sizeof(wchar_t)]; + } buff; + + int j, buff_size, nr, ch_size = getCharSize(VM.CodePage); + int len[max_backward/40]; // suppose minimum line with is 80 chars... + + while ( nlines > 0 ) { - if (off >= line_size) - return off; + if ( fpos <= 0 ) + { + FilePos = 0; + return; + } - wchar_t ch = str[off++]; - width += L'\t' != ch ? 1 : tab_size - width % tab_size; + fpos1 = fpos; - if (width >= Width) + // backward CR-LF search + // + for ( j = 0; j < max_backward/portion_size; ++j ) { - if (!wwrap || wrap_pos <= 0) - return off; - while (wrap_pos < line_size && is_space_or_nul(str[wrap_pos])) - ++wrap_pos; - return wrap_pos; + buff_size = (fpos > (__int64)portion_size ? portion_size : (int)fpos); + fpos -= buff_size; + vseek(fpos, SEEK_SET); + + if ( ch_size <= 1 ) + { + DWORD nread = 0; + Reader.Read(buff.c1, static_cast<DWORD>(buff_size), &nread); + if ((nr = (int)nread) != buff_size) + { + return; //??? error handling + } + if ( 0 == j ) + { + if ( nr > 0 && '\n' == buff.c1[nr-1] ) + { + --nr; + } + if ( nr > 0 && '\r' == buff.c1[nr-1] ) + { + --nr; + } + } + for ( i = nr-1; i >= 0; --i ) + { + if ( '\n' == buff.c1[i] || '\r' == buff.c1[i] ) + break; + } + if ( i >= 0 ) + { + fpos += i + 1; + break; + } + } + else + { + nr = vread(buff.c2, buff_size); + if ( nr != buff_size / ch_size ) + { + return; //??? error handling + } + if ( 0 == j ) + { + if ( nr > 0 && L'\n' == buff.c2[nr-1] ) + { + --nr; + } + if ( nr > 0 && L'\r' == buff.c2[nr-1] ) + { + --nr; + } + } + for ( i = nr-1; i >= 0; --i ) + { + if ( L'\n' == buff.c2[i] || L'\r' == buff.c2[i] ) + break; + } + if ( i >= 0 ) + { + fpos += ch_size * (i + 1); + break; + } + } } - if (!wwrap) - continue; + // split read portion + // + vseek(vString.nFilePos = fpos, SEEK_SET); + for (i = 0; i < (int)ARRAYSIZE(len); ++i) + { + ReadString(&vString, -1, false); + len[i] = (vString.have_eol ? -1 : +1) * vString.linesize; + if ((vString.nFilePos += vString.linesize) >= fpos1) + { + fpos1 = vString.nFilePos; + break; + } + } + assert(i < (int)ARRAYSIZE(len)); + if (i >= (int)ARRAYSIZE(len)) + --i; - if ((wrap_ch = wrapped_char(ch)) >= 0) - wrap_pos = off - 1 + wrap_ch; + while ( i >= 0 ) + { + int l = len[i--]; + bool eol = false; + if (l < 0) + { + eol = true; + l = -l; + } + fpos1 -= l; + CacheLine(fpos1, l, eol); + if (--nlines == 0) + FilePos = fpos1; + } } } -int Viewer::GetStrBytesNum(const wchar_t *Str, int Length) + +int Viewer::GetStrBytesNum( const wchar_t *Str, int Length ) { - if (IsUnicodeCodePage(VM.CodePage)) - return Length; + int ch_size = getCharSize(VM.CodePage); + if (ch_size > 0) + return Length * ch_size; else - return WideCharToMultiByte(VM.CodePage, 0, Str, Length, nullptr, 0, nullptr, nullptr); + return WideCharToMultiByte(VM.CodePage,0, Str,Length, nullptr,0, nullptr,nullptr); } void Viewer::SetViewKeyBar(KeyBar *ViewKeyBar) @@ -1938,7 +2143,6 @@ ChangeViewKeyBar(); } - void Viewer::ChangeViewKeyBar() { if (ViewKeyBar) @@ -1971,6 +2175,7 @@ CtrlObject->Plugins.CurViewer=this; //HostFileViewer; } + enum SEARCHDLG { SD_DOUBLEBOX, @@ -1991,9 +2196,18 @@ enum { - DM_SDSETVISIBILITY = DM_USER+1, + DM_SDSETVISIBILITY = DM_USER + 1, + DM_SDREXVISIBILITY = DM_USER + 2 }; +struct MyDialogData +{ + Viewer *viewer; + bool edit_autofocus; + bool hex_mode; + bool recursive; +}; + INT_PTR WINAPI ViewerSearchDlgProc(HANDLE hDlg,int Msg,int Param1,void* Param2) { switch (Msg) @@ -2010,42 +2224,133 @@ SendDlgMessage(hDlg,DM_SHOWITEM,SD_EDIT_TEXT,ToPtr(!Param1)); SendDlgMessage(hDlg,DM_SHOWITEM,SD_EDIT_HEX,ToPtr(Param1)); SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_CASE,ToPtr(!Param1)); - SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_WORDS,ToPtr(!Param1)); - //SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_REGEXP,!Param1); + int re = SendDlgMessage(hDlg, DM_GETCHECK,SD_CHECKBOX_REGEXP,0) == BSTATE_CHECKED; + int ww = !Param1 && !re; + SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_WORDS,ToPtr(ww)); + SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_REGEXP,ToPtr(!Param1)); + SendDlgMessage(hDlg, DM_SDREXVISIBILITY, re && !Param1, 0); return TRUE; } + case DM_SDREXVISIBILITY: + { + int show = 1; + if ( Param1 ) + { + int tlen = (int)SendDlgMessage(hDlg, DM_GETTEXTPTR, SD_EDIT_TEXT, 0); + show = 0; + if ( tlen > 0 ) + { + RegExp re; + wchar_t t[128], *tmp = t; + if (tlen > (int)ARRAYSIZE(t)) + tmp = new wchar_t[tlen]; + SendDlgMessage(hDlg, DM_GETTEXTPTR, SD_EDIT_TEXT, tmp); + string sre = tmp; + InsertRegexpQuote(sre); + show = re.Compile(sre.CPtr(), OP_PERLSTYLE); + if (tmp != t) + delete[] tmp;; + } + } + SendDlgMessage(hDlg, DM_ENABLE, SD_TEXT_SEARCH, ToPtr(show)); + SendDlgMessage(hDlg, DM_ENABLE, SD_BUTTON_OK, ToPtr(show)); + return TRUE; + } + case DN_KILLFOCUS: + { + if ( SD_EDIT_TEXT == Param1 || SD_EDIT_HEX == Param1 ) + { + MyDialogData *my = (MyDialogData *)SendDlgMessage(hDlg, DM_GETITEMDATA, SD_EDIT_TEXT, 0); + my->hex_mode = (SD_EDIT_HEX == Param1); + } + break; + } case DN_BTNCLICK: { + bool need_focus = false; + MyDialogData *my = (MyDialogData *)SendDlgMessage(hDlg, DM_GETITEMDATA, SD_EDIT_TEXT, 0); + int cradio = (my->hex_mode ? SD_RADIO_HEX : SD_RADIO_TEXT); + if ((Param1 == SD_RADIO_TEXT || Param1 == SD_RADIO_HEX) && Param2) { - SendDlgMessage(hDlg, DM_ENABLEREDRAW, FALSE, 0); - Viewer *viewer = (Viewer *)SendDlgMessage(hDlg, DM_GETITEMDATA, SD_EDIT_TEXT, 0); + need_focus = true; + if ( Param1 != cradio) + { + bool new_hex = (Param1 == SD_RADIO_HEX); - int sd_dst = Param1 == SD_RADIO_HEX ? SD_EDIT_HEX : SD_EDIT_TEXT; - int sd_src = Param1 == SD_RADIO_TEXT ? SD_EDIT_HEX : SD_EDIT_TEXT; + SendDlgMessage(hDlg, DM_ENABLEREDRAW, FALSE, 0); - const wchar_t *ps = (const wchar_t *)SendDlgMessage(hDlg, DM_GETCONSTTEXTPTR, sd_src, 0); - string strTo; - viewer->SearchTextTransform(strTo, ps, Param1 == SD_RADIO_TEXT); + int sd_dst = new_hex ? SD_EDIT_HEX : SD_EDIT_TEXT; + int sd_src = new_hex ? SD_EDIT_TEXT : SD_EDIT_HEX; - SendDlgMessage(hDlg, DM_SETTEXTPTR, sd_dst, const_cast<wchar_t*>(strTo.CPtr())); - SendDlgMessage(hDlg, DM_SDSETVISIBILITY, Param1 == SD_RADIO_HEX, 0); + EditorSetPosition esp; + esp.CurPos = -1; + SendDlgMessage(hDlg, DM_GETEDITPOSITION, sd_src, &esp); + const wchar_t *ps = (const wchar_t *)SendDlgMessage(hDlg, DM_GETCONSTTEXTPTR, sd_src, 0); + string strTo; + my->viewer->SearchTextTransform(strTo, ps, !new_hex, esp.CurPos); - if (!strTo.IsEmpty()) - { - int changed = (int)SendDlgMessage(hDlg, DM_EDITUNCHANGEDFLAG, sd_src, ToPtr(-1)); - SendDlgMessage(hDlg, DM_EDITUNCHANGEDFLAG, sd_dst, ToPtr(changed)); + SendDlgMessage(hDlg, DM_SETTEXTPTR, sd_dst, ToPtr((INT_PTR)strTo.CPtr())); + SendDlgMessage(hDlg, DM_SDSETVISIBILITY, new_hex, 0); + if (esp.CurPos >= 0) + { + int p = esp.CurPos; + if (SendDlgMessage(hDlg, DM_GETEDITPOSITION, sd_dst, &esp)) + { + esp.CurPos = esp.CurTabPos = p; + esp.LeftPos = 0; + SendDlgMessage(hDlg, DM_SETEDITPOSITION, sd_dst, &esp); + } + } + + if (!strTo.IsEmpty()) + { + int changed = (int)SendDlgMessage(hDlg, DM_EDITUNCHANGEDFLAG, sd_src, ToPtr(-1)); + SendDlgMessage(hDlg, DM_EDITUNCHANGEDFLAG, sd_dst, ToPtr(changed)); + } + + SendDlgMessage(hDlg,DM_ENABLEREDRAW,TRUE,0); + my->hex_mode = new_hex; + if ( !my->edit_autofocus ) + return TRUE; } + } + else if ( Param1 == SD_CHECKBOX_REGEXP ) + { + SendDlgMessage(hDlg, DM_SDSETVISIBILITY, my->hex_mode, 0); + } - SendDlgMessage(hDlg,DM_ENABLEREDRAW,TRUE,0); + if ( my->edit_autofocus && !my->recursive ) + { + if ( need_focus + || Param1 == SD_CHECKBOX_CASE + || Param1 == SD_CHECKBOX_WORDS + || Param1 == SD_CHECKBOX_REVERSE + || Param1 == SD_CHECKBOX_REGEXP + ){ + my->recursive = true; + SendDlgMessage(hDlg, DM_SETFOCUS, my->hex_mode ? SD_EDIT_HEX : SD_EDIT_TEXT, 0); + my->recursive = false; + } + } + + if (need_focus) return TRUE; - } + else + break; } + case DN_EDITCHANGE: + { + if ( Param1 == SD_EDIT_TEXT && SendDlgMessage(hDlg,DM_GETCHECK,SD_CHECKBOX_REGEXP,0) == BSTATE_CHECKED ) + SendDlgMessage(hDlg, DM_SDREXVISIBILITY, 1, 0); + break; + } 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); + MyDialogData *my = (MyDialogData *)SendDlgMessage(hDlg, DM_GETITEMDATA, SD_EDIT_TEXT, 0); + SendDlgMessage(hDlg, DM_SETFOCUS, (my->hex_mode ? SD_EDIT_HEX : SD_EDIT_TEXT), 0); return FALSE; } } @@ -2059,10 +2364,13 @@ static void PR_ViewerSearchMsg() { PreRedrawItem preRedrawItem=PreRedraw.Peek(); - ViewerSearchMsg((const wchar_t*)preRedrawItem.Param.Param1,(int)(INT_PTR)preRedrawItem.Param.Param2); + const wchar_t *name = (const wchar_t*)preRedrawItem.Param.Param1; + int percent = (int)(INT_PTR)preRedrawItem.Param.Param2; + int search_hex = (int)(INT_PTR)preRedrawItem.Param.Param3; + ViewerSearchMsg(name, percent, search_hex); } -void ViewerSearchMsg(const wchar_t *MsgStr,int Percent) +void ViewerSearchMsg(const wchar_t *MsgStr, int Percent, int SearchHex) { string strProgress; @@ -2093,6 +2401,7 @@ PreRedrawItem preRedrawItem=PreRedraw.Peek(); preRedrawItem.Param.Param1=(void*)MsgStr; preRedrawItem.Param.Param2=(LPVOID)(INT_PTR)Percent; + preRedrawItem.Param.Param3=(LPVOID)(INT_PTR)SearchHex; PreRedraw.SetParam(preRedrawItem.Param); } @@ -2109,15 +2418,17 @@ } } -static int hex2ss(const wchar_t *from, char *c1, int mb) +static int hex2ss(const wchar_t *from, char *c1, int mb, int *pos = 0) { - int nb, i, v, sub = 0; + int nb, i, v, sub = 0, ps = 0, p0 = (pos ? *pos : -1), p1 = -1; wchar_t ch; nb = i = v = 0; for (;;) { ch = *from++; + ++ps; + if (ch >= L'0' && ch <= L'9') sub = L'0'; else if (ch >= L'A' && ch <= L'F') sub = L'A' - 10; else if (ch >= L'a' && ch <= L'f') sub = L'a' - 10; @@ -2125,6 +2436,8 @@ { if (i > 0) { + if ( p0 >= 0 && ps > p0 && p1 < 0 ) + p1 = nb; c1[nb++] = (char)v; i = 0; } @@ -2136,6 +2449,8 @@ v = v*16 + ((int)ch - sub); if (++i >= 2) { + if ( p0 >= 0 && ps > p0 && p1 < 0 ) + p1 = nb; c1[nb++] = (char)v; i = 0; if (nb >= mb) @@ -2145,10 +2460,12 @@ #ifdef _DEBUG if (nb < mb) c1[nb] = '\0'; #endif + if ( p1 >= 0 && pos ) + *pos = p1; return nb; } -void Viewer::SearchTextTransform( UnicodeString &to, const wchar_t *from, bool hex2text ) +void Viewer::SearchTextTransform( UnicodeString &to, const wchar_t *from, bool hex2text, int &pos ) { int nb, i, v; char c1[128]; @@ -2156,7 +2473,7 @@ if (hex2text) { - nb = hex2ss(from, c1, ARRAYSIZE(c1)); + nb = hex2ss(from, c1, ARRAYSIZE(c1), &pos); if (IsUnicodeCodePage(VM.CodePage)) { @@ -2171,10 +2488,16 @@ ch = 0xffff; // encode L'\0' to += ch; } + if ( pos >= 0 ) + pos /= 2; } else { int nw = MultiByteToWideChar(VM.CodePage,0, c1,nb, ss,ARRAYSIZE(ss)); + if ( pos >= 0 ) + { + pos = MultiByteToWideChar(VM.CodePage,0, c1,pos, NULL,0); + } for (i=0; i < nw; ++i) if (!ss[i]) ss[i] = 0xffff; @@ -2184,8 +2507,12 @@ } else // text2hex { + int ps = 0, pd = 0, p0 = pos, p1 = -1; while (*from) { + if ( ps == p0 ) + p1 = pd; + ++ps; ch = *from++; if (0xffff == ch) // 0xffff - invalid unicode char ch = 0x0000; // it used to transfer '\0' in zero terminated string @@ -2199,398 +2526,737 @@ nb = 2; c1[0] = (char)HIBYTE(ch); c1[1] = (char)LOBYTE(ch); break; default: - nb = WideCharToMultiByte(VM.CodePage,0, &ch, 1, c1, 4, nullptr, nullptr); + nb = WideCharToMultiByte(VM.CodePage,0, &ch,1, c1,4, NULL,NULL); break; } ss2hex(to, c1, nb, L'\0'); + pd += nb * 3; } + pos = p1; } } -/* $ 27.01.2003 VVM - + �������� Next ����� �������� ������: - 0 - ���� ����� - 1 - ��������� ����� �� ������� ������ - 2 - ��������� ����� � ����� ����� -*/ +struct Viewer::search_data +{ + INT64 CurPos; + INT64 MatchPos; + const char *search_bytes; + const wchar_t *search_text; + int search_len; + int ch_size; + bool is_utf8; + bool first_Rex; + RegExp *pRex; -void Viewer::Search(int Next,int FirstChar) -{ - const wchar_t *TextHistoryName=L"SearchText"; - const wchar_t *HexMask=L"HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH "; - FarDialogItem SearchDlgData[]= + search_data() { - {DI_DOUBLEBOX,3,1,72,11,0,nullptr,nullptr,0,MSG(MViewSearchTitle)}, - {DI_TEXT,5,2,0,2,0,nullptr,nullptr,0,MSG(MViewSearchFor)}, - {DI_EDIT,5,3,70,3,0,TextHistoryName,nullptr,DIF_FOCUS|DIF_HISTORY|DIF_USELASTHISTORY,L""}, - {DI_FIXEDIT,5,3,70,3,0,nullptr,HexMask,DIF_MASKEDIT,L""}, - {DI_TEXT,3,4,0,4,0,nullptr,nullptr,DIF_SEPARATOR,L""}, - {DI_RADIOBUTTON,5,5,0,5,1,nullptr,nullptr,DIF_GROUP,MSG(MViewSearchForText)}, - {DI_RADIOBUTTON,5,6,0,6,0,nullptr,nullptr,0,MSG(MViewSearchForHex)}, - {DI_CHECKBOX,40,5,0,5,0,nullptr,nullptr,0,MSG(MViewSearchCase)}, - {DI_CHECKBOX,40,6,0,6,0,nullptr,nullptr,0,MSG(MViewSearchWholeWords)}, - {DI_CHECKBOX,40,7,0,7,0,nullptr,nullptr,0,MSG(MViewSearchReverse)}, - {DI_CHECKBOX,40,8,0,8,0,nullptr,nullptr,DIF_DISABLE,MSG(MViewSearchRegexp)}, - {DI_TEXT,3,9,0,9,0,nullptr,nullptr,DIF_SEPARATOR,L""}, - {DI_BUTTON,0,10,0,10,0,nullptr,nullptr,DIF_DEFAULTBUTTON|DIF_CENTERGROUP,MSG(MViewSearchSearch)}, - {DI_BUTTON,0,10,0,10,0,nullptr,nullptr,DIF_CENTERGROUP,MSG(MViewSearchCancel)}, - }; - MakeDialogItemsEx(SearchDlgData,SearchDlg); - string strSearchStr; - char search_bytes[128]; - string strMsgStr; - __int64 MatchPos=0; - int SearchLength,Case,WholeWords,ReverseSearch,Match,SearchRegexp; + CurPos = MatchPos = -1; + search_bytes = nullptr; + search_text = nullptr; + search_len = ch_size = 0; + is_utf8 = false; + first_Rex = true; + pRex = nullptr; + } - if (!ViewFile.Opened() || (Next && strLastSearchStr.IsEmpty())) - return; + ~search_data() + { + delete pRex; + } +}; - if (!strLastSearchStr.IsEmpty()) - strSearchStr = strLastSearchStr; +int Viewer::search_hex_forward( search_data* sd ) +{ + char *buff = (char *)Search_buffer; + const char *search_str = sd->search_bytes; + int bsize = Search_buffer_size * static_cast<int>(sizeof(wchar_t)), slen = sd->search_len; + INT64 to, cpos = sd->CurPos; + + bool up_half = cpos >= StartSearchPos; + if ( up_half ) + { + if ( (to = FileSize) - cpos <= bsize ) + SetFileSize(); + to = FileSize; + } else - strSearchStr.Clear(); + { + to = StartSearchPos + slen - 1; + if ( to > FileSize ) + to = FileSize; + } - SearchDlg[SD_RADIO_TEXT].Selected=!LastSearchHex; - SearchDlg[SD_RADIO_HEX].Selected=LastSearchHex; - SearchDlg[SD_CHECKBOX_CASE].Selected=LastSearchCase; - SearchDlg[SD_CHECKBOX_WORDS].Selected=LastSearchWholeWords; - SearchDlg[SD_CHECKBOX_REVERSE].Selected=LastSearchReverse; - SearchDlg[SD_CHECKBOX_REGEXP].Selected=LastSearchRegexp; + int nb = (to - cpos < bsize ? static_cast<int>(to - cpos) : bsize); + vseek(cpos, SEEK_SET); + DWORD nr = 0; + Reader.Read(buff, static_cast<DWORD>(nb), &nr); + int n1 = static_cast<int>(nr); + if ( n1 != nb ) + SetFileSize(); - if (SearchFlags.Check(REVERSE_SEARCH)) - SearchDlg[SD_CHECKBOX_REVERSE].Selected=!SearchDlg[SD_CHECKBOX_REVERSE].Selected; + if ( n1 < slen ) + { + if ( !up_half || StartSearchPos <= 0 ) + return -1; + sd->CurPos = 0; + return 0; + } - if (SearchDlg[SD_RADIO_HEX].Selected) + char *ps = buff; + while ( nullptr != (ps = static_cast<char *>(memchr(ps, search_str[0], n1-slen+1))) ) { - int nb = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); - strSearchStr.Clear(); - ss2hex(strSearchStr, search_bytes, nb, L'\0'); - SearchDlg[SD_EDIT_HEX].strData = strSearchStr; + if ( slen <= 1 || 0 == memcmp(ps+1, search_str+1, slen-1) ) + { + sd->MatchPos = cpos + static_cast<INT64>(ps - buff); + return +1; // found + } + ++ps; + n1 = static_cast<int>(nr - (ps - buff)); } + + sd->CurPos = cpos + nr - slen + 1; + return (up_half || sd->CurPos < StartSearchPos ? 0 : -1); +} + +int Viewer::search_hex_backward( search_data* sd ) +{ + char *buff = (char *)Search_buffer; + const char *search_str = sd->search_bytes; + int bsize = Search_buffer_size * static_cast<int>(sizeof(wchar_t)), slen = sd->search_len; + INT64 to, cpos = sd->CurPos; + + bool lo_half = cpos <= StartSearchPos; + if ( lo_half ) + { + to = 0; + } else - SearchDlg[SD_EDIT_TEXT].strData = strSearchStr; + { + to = StartSearchPos - slen + 1; + if ( to < 0 ) + to = 0; + } - SearchDlg[SD_EDIT_TEXT].UserData = this; + int nb = (cpos - to < bsize ? static_cast<int>(cpos - to) : bsize); + vseek(cpos-nb, SEEK_SET); + DWORD nr = 0; + Reader.Read(buff, static_cast<DWORD>(nb), &nr); + int n1 = static_cast<int>(nr); + if ( n1 != nb ) + { + SetFileSize(); + cpos = vtell(); + } - if (!Next) + if ( n1 < slen ) { - SearchFlags.Flags = 0; - Dialog Dlg(SearchDlg,ARRAYSIZE(SearchDlg),ViewerSearchDlgProc); - Dlg.SetPosition(-1,-1,76,13); - Dlg.SetHelp(L"ViewerSearch"); + if ( !lo_half ) + return -1; + SetFileSize(); + if ( StartSearchPos >= FileSize ) + return -1; + sd->CurPos = FileSize; + return 0; + } - if (FirstChar) + for ( char *ps = buff + n1 - 1; ps >= buff + slen - 1; --ps ) + { + if ( *ps == search_str[slen-1] ) { - Dlg.InitDialog(); - Dlg.Show(); - Dlg.ProcessKey(FirstChar); + if ( slen <= 1 || 0 == memcmp(ps-slen+1, search_str, slen-1) ) + { + sd->MatchPos = static_cast<INT64>(cpos-n1+(ps-slen+1-buff)); + return +1; + } } + } - Dlg.Process(); + sd->CurPos = cpos - nr + slen - 1; + return (lo_half || sd->CurPos > StartSearchPos ? 0 : -1); +} - if (Dlg.GetExitCode()!=SD_BUTTON_OK) - return; +int Viewer::search_text_forward( search_data* sd ) +{ + int bsize = 8192, slen = sd->search_len, ww = (LastSearchWholeWords ? 1 : 0); + wchar_t prev_char = L'\0', *buff = Search_buffer, *t_buff = (sd->is_utf8 ? buff + bsize : nullptr); + const wchar_t *search_str = sd->search_text; + INT64 to1, to, cpos = sd->CurPos; + + vseek(cpos, SEEK_SET); + if ( ww ) + prev_char = vgetc_prev(); + + bool up_half = cpos >= StartSearchPos; + if ( up_half ) + { + if ( (to = FileSize) - cpos <= bsize ) + SetFileSize(); + to = FileSize; } + else + { + to = StartSearchPos; + if ( to > FileSize ) + to = FileSize; + } - SearchHex=SearchDlg[SD_RADIO_HEX].Selected; - Case=SearchDlg[SD_CHECKBOX_CASE].Selected; - WholeWords=SearchDlg[SD_CHECKBOX_WORDS].Selected; - ReverseSearch=SearchDlg[SD_CHECKBOX_REVERSE].Selected; - SearchRegexp=SearchDlg[SD_CHECKBOX_REGEXP].Selected; + int nb = (to - cpos > bsize ? bsize : static_cast<int>(to - cpos)); + int nw = vread(buff, nb, t_buff); + to1 = vtell(); + if ( !up_half && nb + 3*(slen+ww) < bsize && !veof() ) + { + int nw1 = vread(buff+nw, 3*(slen+ww), t_buff ? t_buff+nw : nullptr); + nw1 = (nw1 > slen+ww-1 ? slen+ww-1 : nw1); + nw += nw1; + to1 = to + (t_buff ? GetStrBytesNum(t_buff, nw1) : sd->ch_size * nw1); + } - bool t_utf8 = !SearchHex && VM.CodePage == CP_UTF8; + int is_eof = (to1 >= FileSize ? 1 : 0), iLast = nw - slen - ww + is_eof; + if ( !LastSearchCase ) + CharUpperBuff(buff, nw); - if (SearchHex) + for ( int i = 0; i <= iLast; ++i ) { - strSearchStr = SearchDlg[SD_EDIT_HEX].strData; - SearchLength = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); - strSearchStr.Clear(); - ss2hex(strSearchStr, search_bytes, SearchLength, L' '); + if ( ww ) + { + if ( !is_word_div(i > 0 ? buff[i-1] : prev_char)) + continue; + if ( !(i == iLast && is_eof) && !is_word_div(buff[i+slen]) ) + continue; + } + if ( buff[i] != search_str[0] + || (slen > 1 && buff[i+1] != search_str[1]) + || (slen > 2 && 0 != wmemcmp(buff+i+2, search_str+2, slen-2)) + ) continue; + + sd->MatchPos = cpos + GetStrBytesNum(t_buff, i); + sd->search_len = GetStrBytesNum(t_buff+i, slen); + return +1; } + + if ( up_half && is_eof ) + { + sd->CurPos = 0; + return (StartSearchPos > 0 ? 0 : -1); + } else { - strSearchStr = SearchDlg[SD_EDIT_TEXT].strData; - SearchLength = (int)strSearchStr.GetLength(); - size_t pos = 0; - while (strSearchStr.Pos(pos, 0xffff)) - strSearchStr.Replace(pos, 1, L'\0'); + if ( iLast < 0 || (!up_half && to1 > StartSearchPos) ) + return -1; + sd->CurPos = to1; + return 0; } +} - strLastSearchStr = strSearchStr; - LastSearchHex=SearchHex; - LastSearchCase=Case; - LastSearchWholeWords=WholeWords; +int Viewer::search_text_backward( search_data* sd ) +{ + int bsize = 8192, slen = sd->search_len, ww = (LastSearchWholeWords ? 1 : 0); + wchar_t *buff = Search_buffer, *t_buff = (sd->is_utf8 ? buff + bsize : nullptr); + const wchar_t *search_str = sd->search_text; + INT64 to1, to, cpos = sd->CurPos; - if (!SearchFlags.Check(REVERSE_SEARCH)) - LastSearchReverse=ReverseSearch; + bool up_half = cpos > StartSearchPos; + to = (up_half ? StartSearchPos : 0); - LastSearchRegexp=SearchRegexp; + int nb = (cpos - to > bsize ? bsize : static_cast<int>(cpos- to)); + if ( up_half && nb + 3*(slen+ww) < bsize && cpos > nb ) + { + if ( sd->ch_size > 0 ) + { + nb += sd->ch_size * (slen + ww - 1); + if (cpos < nb) + nb = static_cast<int>(cpos); + } + else + { + to1 = cpos - nb - 3*(slen + ww - 1); + if (to1 < 0) + to1 = 0; + int nb1 = static_cast<int>(cpos - nb - to1); + vseek(to1, SEEK_SET); + int nw1 = vread(buff, nb1, t_buff); + if ( nw1 > slen + ww - 1 ) + nb1 = GetStrBytesNum(t_buff + nw1 - (slen + ww - 1), slen + ww - 1); + nb += nb1; + } + } - if (!SearchLength) - return; + cpos -= nb; + vseek(cpos, SEEK_SET); + int nw = vread(buff, nb, t_buff); + if ( !LastSearchCase ) + CharUpperBuff(buff, nw); + int is_eof = (veof() ? 1 : 0), iFirst = ww * (cpos > 0 ? 1 : 0), iLast = nw - slen - ww + ww*is_eof; + for ( int i = iLast; i >= iFirst; --i ) { - TPreRedrawFuncGuard preRedrawFuncGuard(PR_ViewerSearchMsg); - //SaveScreen SaveScr; - SetCursorType(FALSE,0); - strMsgStr = strSearchStr; + if ( ww ) + { + if ( i > 0 && !is_word_div(buff[i-1]) ) + continue; + if ( !(i == iLast && is_eof) && !is_word_div(buff[i+slen]) ) + continue; + } + if ( buff[i] != search_str[0] + || (slen > 1 && buff[i+1] != search_str[1]) + || (slen > 2 && 0 != wmemcmp(buff+i+2, search_str+2, slen-2)) + ) continue; - if (strMsgStr.GetLength()+18 > static_cast<DWORD>(ObjWidth)) - TruncStrFromEnd(strMsgStr, ObjWidth-18); + sd->MatchPos = cpos + GetStrBytesNum(t_buff, i); + sd->search_len = GetStrBytesNum(t_buff+i, slen); + return +1; + } - if (!SearchHex) - InsertQuote(strMsgStr); + int ret = 0; + if ( up_half ) + ret = (cpos <= StartSearchPos ? -1 : 0); + else + { + if ( cpos <= 0 ) + { + SetFileSize(); + cpos = FileSize; + ret = (StartSearchPos >= FileSize ? -1 : 0); + } + } + sd->CurPos = cpos; + return ret; +} - if (SearchHex) - Case = 1 + (WholeWords = 0); +int Viewer::read_line(wchar_t *buf, wchar_t *tbuf, INT64 cpos, int adjust, INT64 &lpos, int &lsize) +{ + int llen = 0; - if (!Case && !SearchHex) - strSearchStr.Upper(); + INT64 save_FilePos = FilePos, save_LastPage = LastPage; + int save_Hex = VM.Hex, save_Wrap = VM.Wrap, save_WordWrap = VM.WordWrap; + VM.Hex = VM.Wrap = VM.WordWrap = 0; - SelectSize = 0; + FilePos = cpos; + if ( adjust ) + { + if ( adjust > 0 ) + AdjustFilePos(); + else + Up(1); + } - if (Next) + vseek(lpos = vString.nFilePos = FilePos, SEEK_SET); + vString.linesize = 0; + ReadString(&vString, -1, false); // read unwrapped text line + + vseek(FilePos, SEEK_SET); + llen = vread(buf, lsize = vString.linesize, tbuf); + if ( llen > 0 && vString.have_eol ) // remove eol-s + { + --llen; + if ( llen > 0 && (buf[llen-1] == L'\r') || buf[llen-1] == L'\n' ) + --llen; + } + buf[llen >= 0 ? llen : 0] = L'\0'; + + VM.Hex = save_Hex; VM.Wrap = save_Wrap; VM.WordWrap = save_WordWrap; + FilePos = save_FilePos; LastPage = save_LastPage; + return llen; +} + +int Viewer::search_regex_forward( search_data* sd ) +{ + assert(sd->pRex); + assert(Search_buffer_size >= 2*MAX_VIEWLINEB); + + wchar_t *line = Search_buffer, *t_line = sd->is_utf8 ? Search_buffer + MAX_VIEWLINEB : nullptr; + INT64 cpos = sd->CurPos, bpos = 0; + + int first = (sd->first_Rex ? +1 : 0); + sd->first_Rex = false; + bool up_half = cpos >= StartSearchPos; + + int lsize = 0, nw = read_line(line, t_line, cpos, first, bpos, lsize); + if ( lsize <= 0 ) + { + sd->CurPos = 0; + return (up_half && StartSearchPos > 0 ? 0 : -1); + } + + int off = 0; + for (;;) + { + if ( off > nw ) + break; + + SMatch m[1]; + int n = static_cast<int>(ARRAYSIZE(m)); + if ( !sd->pRex->SearchEx(line, line+off, line+nw, m, n) ) // doesn't match + break; + + INT64 fpos = bpos + GetStrBytesNum(t_line, m[0].start); + if ( fpos < cpos ) { - if (Next == 2) - { - SearchFlags.Set(SEARCH_MODE2); - LastSelPos = ReverseSearch?FileSize:0; - } - else - { - LastSelPos = SelectPos + (ReverseSearch?-1:1); - } + off = m[0].start + 1; // skip + continue; } - else + else if ( !up_half && fpos >= StartSearchPos ) { - LastSelPos = FilePos; + break; // done - not found + } + else // found + { + sd->MatchPos = fpos; + sd->search_len = GetStrBytesNum(t_line+off, m[0].end - m[0].start); + return +1; + } + } - if (!LastSelPos || LastSelPos == FileSize) - SearchFlags.Set(SEARCH_MODE2); + sd->CurPos = vtell(); + if ( up_half ) + { + if ( veof() ) + { + sd->CurPos = 0; + return (StartSearchPos > 0 ? 0 : -1); } + return 0; + } + else + { + return (sd->CurPos >= StartSearchPos ? -1 : 0); + } +} - vseek(LastSelPos,SEEK_SET); - Match = 0; +int Viewer::search_regex_backward( search_data* sd ) +{ + assert(sd->pRex); + assert(Search_buffer_size >= 2*MAX_VIEWLINEB); - if (SearchLength > 0 && (!ReverseSearch || LastSelPos > 0)) + wchar_t *line = Search_buffer, *t_line = sd->is_utf8 ? Search_buffer + MAX_VIEWLINEB : nullptr; + INT64 cpos = sd->CurPos, bpos = 0, prev_pos = -1; + + bool up_half = cpos > StartSearchPos; + + int off=0, lsize=0, nw, prev_len = -1, flen; + nw = read_line(line, t_line, cpos, -1, bpos, lsize); + for (;;) + { + if ( lsize <= 0 || off > nw ) + break; + + SMatch m[1]; + int n = static_cast<int>(ARRAYSIZE(m)); + if ( !sd->pRex->SearchEx(line, line+off, line+nw, m, n) ) + break; + + INT64 fpos = bpos + GetStrBytesNum(t_line, m[0].start); + flen = GetStrBytesNum(t_line + m[0].start, m[0].end - m[0].start); + if ( fpos+flen > cpos ) + break; + + if ( !(up_half && fpos+flen <= StartSearchPos) ) { - wchar_t *Buf = new wchar_t[8192 + 8192], *t_Buf = t_utf8 ? Buf + 8192 : nullptr; - int buf_size = 8192, seek_size = 1; - char *byte_buff = nullptr; - if (SearchHex) - { - byte_buff = (char *)Buf; - buf_size *= 2*(int)sizeof(wchar_t); - seek_size = IsUnicodeCodePage(VM.CodePage) ? 2 : 1; - } + prev_pos = fpos; + prev_len = flen; + } - __int64 CurPos=LastSelPos; - int BufSize = buf_size; + off = m[0].start + 1; // skip + continue; + } - if (ReverseSearch) - { - /* $ 01.08.2000 KM - ������� �������� CurPos � ���� Whole words - */ - if (WholeWords) - CurPos -= BufSize/seek_size - SearchLength/seek_size + 1; - else - CurPos -= BufSize/seek_size - SearchLength/seek_size; + if ( prev_len >= 0 ) + { + sd->MatchPos = prev_pos; + sd->search_len = prev_len; + return +1; + } + + if ( (sd->CurPos = bpos) <= 0 ) + { + SetFileSize(); + sd->CurPos = FileSize; + return (StartSearchPos >= FileSize ? -1 : 0); + } + return (up_half && bpos <= StartSearchPos ? -1 : 0); +} - if (CurPos<0) - BufSize += (int)CurPos * seek_size; - } - int ReadSize; - TaskBar TB; - wakeful W; - INT64 StartPos = vtell(); - DWORD StartTime = GetTickCount(); +/* + + �������� Next ����� �������� ������: + 0 - ���� ����� + 1 - ��������� ����� �� ������� ������ +-1 - ��������� ����� �� ������� ������ � ��������������� ����������� + 2 - ��������� ����� � �����/���� ����� +*/ +void Viewer::Search(int Next,int FirstChar) +{ + if (!ViewFile.Opened() || (Next && strLastSearchStr.IsEmpty())) + return; - while (!Match) - { - /* $ 01.08.2000 KM - �������� ������ if (ReverseSearch && CurPos<0) �� if (CurPos<0), - ��� ��� ��� ����� ����� � LastSelPos=0xFFFFFFFF, ����� - ���������� ��� � �� ������. - */ - if (CurPos < 0) - CurPos = 0; + string strSearchStr, strMsgStr; + char search_bytes[128]; + int Case,WholeWords,ReverseSearch,SearchRegexp,SearchHex; - vseek(CurPos, SEEK_SET); + SearchHex = LastSearchHex; + Case = LastSearchCase; + WholeWords = LastSearchWholeWords; + ReverseSearch = LastSearchReverse; + SearchRegexp = LastSearchRegexp; + strSearchStr.Clear(); + if (!strLastSearchStr.IsEmpty()) + strSearchStr = strLastSearchStr; - if (SearchHex) - { - DWORD nr = 0; - Reader.Read(byte_buff, (DWORD)BufSize, &nr); - ReadSize = (int)nr; - } - else - { - ReadSize = vread(Buf, BufSize, t_Buf); - } - if (ReadSize <= 0) - break; + search_data sd; + int (Viewer::* searcher)( Viewer::search_data *p_sd ) = nullptr; - DWORD CurTime=GetTickCount(); + if ( !Next ) + { + const wchar_t *TextHistoryName=L"SearchText"; + const wchar_t *HexMask = L"HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH " ; + FarDialogItem SearchDlgData[]= + { + {DI_DOUBLEBOX,3,1,72,11,0,nullptr,nullptr,0,MSG(MViewSearchTitle)}, + {DI_TEXT,5,2,0,2,0,nullptr,nullptr,0,MSG(MViewSearchFor)}, + {DI_EDIT,5,3,70,3,0,TextHistoryName,nullptr,DIF_FOCUS|DIF_HISTORY|DIF_USELASTHISTORY,L""}, + {DI_FIXEDIT,5,3,70,3,0,nullptr,HexMask,DIF_MASKEDIT,L""}, + {DI_TEXT,3,4,0,4,0,nullptr,nullptr,DIF_SEPARATOR,L""}, + {DI_RADIOBUTTON,5,5,0,5,1,nullptr,nullptr,DIF_GROUP,MSG(MViewSearchForText)}, + {DI_RADIOBUTTON,5,6,0,6,0,nullptr,nullptr,0,MSG(MViewSearchForHex)}, + {DI_CHECKBOX,40,5,0,5,0,nullptr,nullptr,0,MSG(MViewSearchCase)}, + {DI_CHECKBOX,40,6,0,6,0,nullptr,nullptr,0,MSG(MViewSearchWholeWords)}, + {DI_CHECKBOX,40,7,0,7,0,nullptr,nullptr,0,MSG(MViewSearchReverse)}, + {DI_CHECKBOX,40,8,0,8,0,nullptr,nullptr,DIF_DISABLE,MSG(MViewSearchRegexp)}, + {DI_TEXT,3,9,0,9,0,nullptr,nullptr,DIF_SEPARATOR,L""}, + {DI_BUTTON,0,10,0,10,0,nullptr,nullptr,DIF_DEFAULTBUTTON|DIF_CENTERGROUP,MSG(MViewSearchSearch)}, + {DI_BUTTON,0,10,0,10,0,nullptr,nullptr,DIF_CENTERGROUP,MSG(MViewSearchCancel)}, + }; + MakeDialogItemsEx(SearchDlgData,SearchDlg); - if (CurTime-StartTime>RedrawTimeout) - { - StartTime=CurTime; + SearchDlg[SD_RADIO_TEXT].Selected=!LastSearchHex; + SearchDlg[SD_RADIO_HEX].Selected=LastSearchHex; + SearchDlg[SD_CHECKBOX_CASE].Selected=LastSearchCase; + SearchDlg[SD_CHECKBOX_WORDS].Selected=LastSearchWholeWords; + SearchDlg[SD_CHECKBOX_REVERSE].Selected=LastSearchReverse; + SearchDlg[SD_CHECKBOX_REGEXP].Selected=LastSearchRegexp; - if (CheckForEscSilent()) - { - if (ConfirmAbortOp()) - { - Redraw(); - return; - } - } + if (SearchDlg[SD_RADIO_HEX].Selected) + { + int nb = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); + strSearchStr.Clear(); + ss2hex(strSearchStr, search_bytes, nb, L'\0'); + SearchDlg[SD_EDIT_HEX].strData = strSearchStr; + } + else + SearchDlg[SD_EDIT_TEXT].strData = strSearchStr; - INT64 Total=ReverseSearch?StartPos:FileSize-StartPos; - INT64 Current=_abs64(CurPos-StartPos); - int Percent=Total>0?static_cast<int>(Current*100/Total):-1; - // � ����� ���� ���� ����������� �������, �� ��������� - // �������� ����� �� ���� 100. ����������� ��� ������. - if (Percent>100) - { - SetFileSize(); - Total=FileSize-StartPos; - Percent=Total>0?static_cast<int>(Current*100/Total):-1; - if (Percent>100) - { - Percent=100; - } - } - ViewerSearchMsg(strMsgStr,Percent); - } + MyDialogData my; + // + my.viewer = this; + my.edit_autofocus = (ViOpt.SearchEditFocus != 0); + my.hex_mode = (LastSearchHex != 0); + my.recursive = false; + // + SearchDlg[SD_EDIT_TEXT].UserData = &my; - /* $ 01.08.2000 KM - ������� ����� �������� �� Case sensitive � Hex - � ���� ���, ����� Buf ��������� � ������� �������� - */ - if (!Case && !SearchHex) - CharUpperBuff(Buf, ReadSize); + Dialog Dlg(SearchDlg,ARRAYSIZE(SearchDlg),ViewerSearchDlgProc); + Dlg.SetPosition(-1,-1,76,13); + Dlg.SetHelp(L"ViewerSearch"); - /* $ 01.08.2000 KM - ����� ����� ������ ����� ��������� ��������� ������ - � Buf � ������� ��������, ���� ����� �� ���������������� - ��� �� ���� Hex-������ � � ���� � ���� ����������� ��� ������ - */ - int MaxSize=ReadSize-SearchLength+1; - int Increment=ReverseSearch ? -seek_size : +seek_size; + if (FirstChar) + { + Dlg.InitDialog(); + Dlg.Show(); + Dlg.ProcessKey(FirstChar); + } - for (int I=ReverseSearch ? MaxSize-1:0; I<MaxSize && I>=0; I+=Increment) - { - /* $ 01.08.2000 KM - ��������� ������ "Whole words" - */ - int locResultLeft=FALSE; - int locResultRight=FALSE; + Dlg.Process(); - if (WholeWords) - { - if (I) - { - if (IsSpace(Buf[I-1]) || IsEol(Buf[I-1]) || - (wcschr(Opt.strWordDiv,Buf[I-1]))) - locResultLeft=TRUE; - } - else - { - locResultLeft=TRUE; - } + if (Dlg.GetExitCode()!=SD_BUTTON_OK) + return; - if (ReadSize!=BufSize && I+SearchLength>=ReadSize) - locResultRight=TRUE; - else if (I+SearchLength<ReadSize && - (IsSpace(Buf[I+SearchLength]) || IsEol(Buf[I+SearchLength]) || - (wcschr(Opt.strWordDiv,Buf[I+SearchLength])))) - locResultRight=TRUE; - } - else - { - locResultLeft=TRUE; - locResultRight=TRUE; - } + SearchHex=SearchDlg[SD_RADIO_HEX].Selected; + Case=SearchDlg[SD_CHECKBOX_CASE].Selected; + WholeWords=SearchDlg[SD_CHECKBOX_WORDS].Selected; + ReverseSearch=SearchDlg[SD_CHECKBOX_REVERSE].Selected; + SearchRegexp=SearchDlg[SD_CHECKBOX_REGEXP].Selected; - if (!SearchHex) - { - Match = locResultLeft && locResultRight && strSearchStr.At(0) == Buf[I] && - ( SearchLength==1 || - ( strSearchStr.At(1) == Buf[I+1] && - (SearchLength==2 || !memcmp(strSearchStr.CPtr()+2,&Buf[I+2],(SearchLength-2)*sizeof(wchar_t))) - ) - ) - ; - } - else - { - if ((Match = search_bytes[0] == byte_buff[I+0]) && SearchLength > 1) - if ((Match = search_bytes[1] == byte_buff[I+1]) && SearchLength > 2) - if ((Match = search_bytes[2] == byte_buff[I+2]) && SearchLength > 3) - if ((Match = search_bytes[3] == byte_buff[I+3]) && SearchLength > 4) - Match = !memcmp(search_bytes+4, byte_buff+I+4, SearchLength-4); - } + if (SearchHex) + { + strSearchStr = SearchDlg[SD_EDIT_HEX].strData; + int len = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); + strSearchStr.Clear(); + ss2hex(strSearchStr, search_bytes, len, L' '); + } + else + { + strSearchStr = SearchDlg[SD_EDIT_TEXT].strData; + size_t pos = 0; + while (strSearchStr.Pos(pos, 0xffff)) + strSearchStr.Replace(pos, 1, L'\0'); + } + } - if (Match) + LastSearchCase = Case; + LastSearchWholeWords = WholeWords; + LastSearchReverse = ReverseSearch; + LastSearchRegexp = SearchRegexp; + + if (Next == -1) + ReverseSearch = !ReverseSearch; + + strMsgStr = strLastSearchStr = strSearchStr; + if (strMsgStr.GetLength()+18 > static_cast<DWORD>(ObjWidth)) + TruncStrFromEnd(strMsgStr, ObjWidth-18); + + sd.search_len = (int)strSearchStr.GetLength(); + if (0 != (LastSearchHex = SearchHex)) + { + sd.search_len = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); + sd.search_bytes = search_bytes; + sd.ch_size = 1; + Case = 1 + (WholeWords = SearchRegexp = 0); + searcher = (ReverseSearch ? &Viewer::search_hex_backward : &Viewer::search_hex_forward); + } + else + { + sd.is_utf8 = VM.CodePage == CP_UTF8; + sd.ch_size = getCharSize(VM.CodePage); + sd.search_text = strSearchStr.CPtr(); + + if ( SearchRegexp ) + { + WholeWords = 0; + searcher = (ReverseSearch ? &Viewer::search_regex_backward : &Viewer::search_regex_forward); + InsertRegexpQuote(strMsgStr); + sd.pRex = new RegExp; + string strSlash = strSearchStr; + InsertRegexpQuote(strSlash); + if ( !sd.pRex->Compile(strSlash, OP_PERLSTYLE | OP_OPTIMIZE | (Case ? 0 : OP_IGNORECASE)) ) + return; // wrong regular expression... + } + else + { + searcher = (ReverseSearch ? &Viewer::search_text_backward : &Viewer::search_text_forward); + InsertQuote(strMsgStr); + } + } + + if (!Case && !SearchRegexp) + { + strSearchStr.Upper(); + sd.search_text = strSearchStr.CPtr(); + } + + int found = 0; + + int search_direction = ReverseSearch ? -1 : +1; + switch (Next) + { + case 2: + StartSearchPos = LastSelectPos = (ReverseSearch ? FileSize : 0); + break; + case +1: case -1: + if ( SelectPos >= 0 && LastSelectSize >= 0 ) + { + if (sd.ch_size >= 1) + LastSelectPos = SelectPos + (ReverseSearch ? LastSelectSize-sd.ch_size : sd.ch_size); + else + { + INT64 prev_pos = SelectPos; + vseek(SelectPos, SEEK_SET); + for (;;) { - MatchPos = CurPos + I / seek_size; - if (t_utf8) + wchar_t ch; + bool ok_getc = vgetc(&ch); + LastSelectPos = vtell(); + if (!ReverseSearch || !ok_getc) + break; + if ( LastSelectPos >= SelectPos + LastSelectSize ) { - MatchPos = CurPos + GetStrBytesNum(t_Buf, I); - SearchLength = GetStrBytesNum(t_Buf+I, SearchLength); + LastSelectPos = prev_pos; + break; } - break; + prev_pos = LastSelectPos; } } + if (search_direction != LastSearchDirection) + StartSearchPos = LastSelectPos; + else if ( LastSelectPos == StartSearchPos ) // ������ � + found = -1; // ������������ - if ((ReverseSearch && CurPos <= 0) || (!ReverseSearch && veof())) - break; + break; + } // else pass to case 0 (below) + case 0: + LastSelectSize = SelectSize = -1; + StartSearchPos = LastSelectPos = (ReverseSearch ? EndOfScreen(0) : BegOfScreen()); + break; + } + LastSearchDirection = search_direction; - int asz = buf_size; - if (t_utf8) - asz = GetStrBytesNum(t_Buf, ReadSize); + if (!sd.search_len || (__int64)sd.search_len > FileSize) + return; - if (ReverseSearch) + sd.CurPos = LastSelectPos; + if ( !found ) + { + TPreRedrawFuncGuard preRedrawFuncGuard(PR_ViewerSearchMsg); + SetCursorType(FALSE,0); + + DWORD start_time = GetTickCount(); + for (;;) + { + found = (this->*searcher)(&sd); + if ( found != 0 ) + break; + + DWORD cur_time = GetTickCount(); + if ( cur_time - start_time > RedrawTimeout ) + { + start_time = cur_time; + + if (CheckForEscSilent()) { - /* $ 01.08.2000 KM - ������� �������� CurPos � ���� Whole words - */ - if (WholeWords) - CurPos -= asz/seek_size - SearchLength/seek_size + 1; - else - CurPos -= asz/seek_size - SearchLength/seek_size; + if (ConfirmAbortOp()) + { + Redraw(); + return; + } } - else + + int percent = -1; + INT64 done, total = FileSize; + if ( total > 0 ) { - if (WholeWords) - CurPos += asz/seek_size - SearchLength/seek_size + 1; + if ( !ReverseSearch ) + { + if ( sd.CurPos >= StartSearchPos ) + done = sd.CurPos - StartSearchPos; + else + done = (FileSize - StartSearchPos) + sd.CurPos; + } else - CurPos += asz/seek_size - SearchLength/seek_size; + { + if ( sd.CurPos <= StartSearchPos ) + done = StartSearchPos - sd.CurPos; + else + done = StartSearchPos + (FileSize - sd.CurPos); + } + percent = static_cast<int>(done*100/total); } + ViewerSearchMsg(strMsgStr, percent, SearchHex); } - - delete[] Buf; } } - if (Match) + if ( sd.MatchPos >= 0 ) { - /* $ 24.01.2003 KM - ! �� �������� ������ �������� �� ���� ������ �� - ���� ������������ ����. - */ - SelectText(MatchPos,SearchLength,ReverseSearch?0x2:0); - // ������� ��������� �� ��������� ����� ������ �� ����. + SelectText(sd.MatchPos, sd.search_len, ReverseSearch?0x2:0); + LastSelectSize = SelectSize; + + // ������� ��������� �� ��������� �������� ������ �� ����. int FromTop=(ScrY-(Opt.ViOpt.ShowKeyBar?2:1))/4; if (FromTop<0 || FromTop>ScrY) FromTop=0; - for (int i=0; i<FromTop; i++) - Up(); + Up(FromTop); AdjustSelPosition = TRUE; Show(); @@ -2598,24 +3264,13 @@ } else { - //Show(); - /* $ 27.01.2003 VVM - + ����� ������� ������ ������� � ������� ������ � �����/���� */ - if (SearchFlags.Check(SEARCH_MODE2)) - { - Message(MSG_WARNING,1,MSG(MViewSearchTitle), - (SearchHex?MSG(MViewSearchCannotFindHex):MSG(MViewSearchCannotFind)),strMsgStr,MSG(MOk)); - } - else - { - if (!Message(MSG_WARNING,2,MSG(MViewSearchTitle), - (SearchHex?MSG(MViewSearchCannotFindHex):MSG(MViewSearchCannotFind)),strMsgStr, - (ReverseSearch?MSG(MViewSearchFromEnd):MSG(MViewSearchFromBegin)), - MSG(MHYes),MSG(MHNo))) - { - Search(2,0); - } - } + Message( + MSG_WARNING, 1, + MSG(MViewSearchTitle), + (SearchHex ? MSG(MViewSearchCannotFindHex) : MSG(MViewSearchCannotFind)), + strMsgStr, + MSG(MOk) + ); } } @@ -2625,37 +3280,31 @@ 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; @@ -2663,7 +3312,6 @@ ConsoleTitle::SetFarTitle(strTitle); } - void Viewer::SetTempViewName(const wchar_t *Name, BOOL DeleteFolder) { if (Name && *Name) @@ -2677,7 +3325,6 @@ Viewer::DeleteFolder=DeleteFolder; } - void Viewer::SetTitle(const wchar_t *Title) { if (!Title) @@ -2686,19 +3333,16 @@ 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) @@ -2825,10 +3469,15 @@ if (IsUnicodeCodePage(VM.CodePage)) { - Reader.Read(Buf, Count*2, &ReadSize); + int rev = (CP_REVERSEBOM == VM.CodePage ? 1 : 0); + + Reader.Read(Buf, Count, &ReadSize); if (0 != (ReadSize & 1)) - ((char *)Buf)[ReadSize++] = '\0'; - + { + ((char *)Buf)[ReadSize-1+rev] = (char)(REPLACE_CHAR & 0xff); + ((char *)Buf)[ReadSize-0-rev] = (char)(REPLACE_CHAR >> 8); + ++ReadSize; + } if (CP_REVERSEBOM == VM.CodePage) { for (DWORD i=0; i<ReadSize; i+=2) @@ -2838,7 +3487,6 @@ ((char *)Buf)[i+1] = t; } } - ReadSize /= 2; } else @@ -2871,15 +3519,11 @@ bool Viewer::vseek(__int64 Offset, int Whence) { - int seek_size = IsUnicodeCodePage(VM.CodePage) ? 2 : 1; - Offset *= seek_size; - if (FILE_CURRENT == Whence) { if (vgetc_ready) { int tail = vgetc_cb - vgetc_ib; - tail += (seek_size - 1) * (tail & 1); Offset += tail; vgetc_ready = false; } @@ -2898,9 +3542,6 @@ if (vgetc_ready) Ptr -= (vgetc_cb - vgetc_ib); - if (IsUnicodeCodePage(VM.CodePage)) - Ptr=(Ptr+(Ptr&1))/2; - return Ptr; } @@ -2927,9 +3568,6 @@ DWORD nr = 0; Reader.Read(vgetc_buffer + vgetc_cb, (DWORD)(ARRAYSIZE(vgetc_buffer)-vgetc_cb), &nr); vgetc_cb += (int)nr; - - if (0 != (vgetc_cb & 1) && IsUnicodeCodePage(VM.CodePage)) - vgetc_buffer[vgetc_cb++] = 0; } vgetc_ready = true; @@ -2951,11 +3589,17 @@ switch (VM.CodePage) { case CP_REVERSEBOM: - *pCh = (wchar_t)((vgetc_buffer[vgetc_ib] << 8) | vgetc_buffer[vgetc_ib+1]); + if (vgetc_ib == vgetc_cb-1) + *pCh = REPLACE_CHAR; + else + *pCh = (wchar_t)((vgetc_buffer[vgetc_ib] << 8) | vgetc_buffer[vgetc_ib+1]); vgetc_ib += 2; break; case CP_UNICODE: - *pCh = (wchar_t)((vgetc_buffer[vgetc_ib+1] << 8) | vgetc_buffer[vgetc_ib]); + if (vgetc_ib == vgetc_cb-1) + *pCh = REPLACE_CHAR; + else + *pCh = (wchar_t)((vgetc_buffer[vgetc_ib+1] << 8) | vgetc_buffer[vgetc_ib]); vgetc_ib += 2; break; case CP_UTF8: @@ -2978,6 +3622,54 @@ return true; } +wchar_t Viewer::vgetc_prev() +{ + INT64 pos = vtell(); + if ( pos <= 0 ) + return L'\0'; + + int ch_size = getCharSize(VM.CodePage); + if ( pos < ch_size ) + return REPLACE_CHAR; + + int nb = (ch_size >= 1 ? ch_size : (pos > 4 ? 4 : static_cast<int>(pos))); + DWORD nr = 0; + + char ss[4]; + if ( vseek(-nb, SEEK_CUR) ) + Reader.Read(ss, static_cast<DWORD>(nb), &nr); + + vseek(pos, SEEK_SET); + + wchar_t ch = REPLACE_CHAR; + if ( static_cast<int>(nr) == nb ) + { + switch ( VM.CodePage ) + { + case CP_REVERSEBOM: + ch = MAKEWORD(ss[1], ss[0]); + break; + case CP_UNICODE: + ch = MAKEWORD(ss[0], ss[1]); + break; + case CP_UTF8: + { + int tail = 0; + wchar_t w[4]; + int nw = utf8_to_WideChar(ss, nb, w,nullptr, 4,tail); + if ( !tail && nw > 0 ) + ch = w[nw-1]; + break; + } + default: + MultiByteToWideChar(VM.CodePage, 0, (LPCSTR)ss,1, &ch,1); + break; + } + } + return ch; +} + + #define RB_PRC 3 #define RB_HEX 4 #define RB_DEC 5 @@ -3060,9 +3752,6 @@ // Percent=0; Offset=FileSize/100*Percent; - if (IsUnicodeCodePage(VM.CodePage)) - Offset*=2; - while (ToPercent64(Offset,FileSize)<Percent) Offset++; } @@ -3094,31 +3783,16 @@ // Percent=0; Offset=FileSize/100*Percent; - if (IsUnicodeCodePage(VM.CodePage)) - Offset*=2; - while (ToPercent64(Offset,FileSize)<Percent) Offset++; } } - if (Relative) - { - if (Relative==-1 && Offset>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; // ��� ��� ����� ����� ���� + FilePos = (Relative ? FilePos + Offset*Relative : Offset); + FilePos = (FilePos < 0 ? 0 : (FilePos > FileSize ? FileSize : FilePos)); } - // ������� AdjustFilePos(); -// LastSelPos=FilePos; if (!(Flags&VSP_NOREDRAW)) Show(); } @@ -3129,6 +3803,9 @@ if (!VM.Hex) { + int ch_size = getCharSize(VM.CodePage); + FilePos -= FilePos % ch_size; + vseek(FilePos, SEEK_SET); if (VM.CodePage != CP_UTF8) { @@ -3140,7 +3817,7 @@ if (vgetc_ib < vgetc_cb) { if (0x80 == (vgetc_buffer[vgetc_ib] & 0xC0)) - { + { if (++vgetc_ib < vgetc_cb) { if (0x80 == (vgetc_buffer[vgetc_ib] & 0xC0)) @@ -3152,18 +3829,18 @@ } } } - } + } else - { + { vgetc(&ch); } } } - FilePos = vtell(); - Up(); - } + FilePos = vtell(); + Up(1); } +} void Viewer::SetFileSize() { @@ -3173,13 +3850,6 @@ UINT64 uFileSize=0; // BUGBUG, sign ViewFile.GetSize(uFileSize); FileSize=uFileSize; - - /* $ 20.02.2003 IS - ����� ���������� FilePos � FileSize, FilePos �� ������� ������ - �������� � ��� ����, ������ FileSize ���� ���� ������ - */ - if (IsUnicodeCodePage(VM.CodePage)) - FileSize=(FileSize+(FileSize&1))/2; } @@ -3190,85 +3860,50 @@ Flags=SelectFlags; } -/* $ 19.01.2001 SVS - �������� - � ������� ������������� ������. - Flags=0x01 - �������� (����� Show()) - 0x02 - "������� �����" ? -*/ -void Viewer::SelectText(const __int64 &MatchPos,const __int64 &SearchLength, const DWORD Flags) +// Flags=0x01 - �������� [����� Show()] +// 0x02 - "������� �����" ? +// +void Viewer::SelectText(const __int64 &match_pos,const __int64 &search_len, const DWORD flags) { if (!ViewFile.Opened()) return; - int buff_size = 1024; - wchar_t *Buf = Up_buffer, *tBuf = (!VM.Hex && VM.CodePage == CP_UTF8) ? Buf + buff_size : nullptr; - __int64 StartLinePos = -1, SearchLinePos = MatchPos - buff_size; - if (SearchLinePos < 0) - { - buff_size += (int)SearchLinePos; - SearchLinePos = 0; - } + SelectPos = match_pos; + SelectSize = search_len; + SelectFlags = flags; + if ( SelectSize < 0 ) + return; - vseek(SearchLinePos, SEEK_SET); - int ReadSize = vread(Buf, buff_size, tBuf); - - for (int I=ReadSize-1; I >= 0; I--) - if (Buf[I]==L'\n' || Buf[I]==L'\r') + if ( VM.Hex ) { - if (tBuf) - StartLinePos = MatchPos - GetStrBytesNum(tBuf+I, ReadSize-I); - else - StartLinePos = SearchLinePos+I; - break; + FilePos = (FilePos & 0xf) | (SelectPos & ~0xf); + FilePos = (FilePos < SelectPos ? FilePos : (FilePos > 16 ? FilePos-16 : 0)); } - - vseek(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) + FilePos = SelectPos; + Up(1); + LeftPos = 0; + + if ( !VM.Wrap ) { - Up(); - Show(); //update OutStr - } + vseek(vString.nFilePos = FilePos, SEEK_SET); + vString.lpData[0] = L'\0'; + ReadString(&vString, (int)(SelectPos-FilePos)); - /* $ 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; + wchar_t first_found_char = L'\0'; + vgetc(&first_found_char); - if (VM.Wrap) - Length%=Width+1; //?? - - if (Length<=Width) - LeftPos=0; - - if (Length-LeftPos>Width || Length<LeftPos) - { - LeftPos=Length; - - if (LeftPos>(MAX_VIEWLINE-1) || LeftPos<0) - LeftPos=0; - else if (LeftPos>10) - LeftPos-=10; + if ( L'\r' != first_found_char && L'\n' != first_found_char ) + { + int found_offset = (int)wcslen(vString.lpData); + if ( found_offset > Width-10 ) + LeftPos = (Width <= 10 ? found_offset : found_offset + 10 - Width); + } } } - if (Flags&1) + if (0 != (flags & 1)) { AdjustSelPosition = TRUE; Show(); @@ -3276,6 +3911,7 @@ } } + int Viewer::ViewerControl(int Command,void *Param) { switch (Command) @@ -3365,7 +4001,7 @@ } else { - SelectSize = 0; + SelectSize = -1; Show(); } @@ -3476,7 +4112,6 @@ Show(); } -// LastSelPos=FilePos; return oldHex; } @@ -3488,7 +4123,7 @@ if (VM.Wrap) LeftPos = 0; - if (!VM.Wrap) + if (!VM.Hex) AdjustFilePos(); if (isRedraw) @@ -3498,7 +4133,6 @@ } Opt.ViOpt.ViewerIsWrap=VM.Wrap; -// LastSelPos=FilePos; return oldWrap; } @@ -3513,6 +4147,9 @@ LeftPos = 0; } + if (!VM.Hex) + AdjustFilePos(); + if (isRedraw) { ChangeViewKeyBar(); @@ -3520,6 +4157,5 @@ } Opt.ViOpt.ViewerWrap=VM.WordWrap; -//LastSelPos=FilePos; return oldTypeWrap; } Index: config.cpp =================================================================== --- config.cpp (revision 6286) +++ config.cpp (working copy) @@ -595,6 +595,9 @@ {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"PersistentBlocks",&Opt.ViOpt.PersistentBlocks,0, 0}, {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"AnsiCodePageAsDefault",&Opt.ViOpt.AnsiCodePageAsDefault,1, 0}, + {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"MaxLineSize",&Opt.ViOpt.MaxLineSize,2048, 0}, + {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"SearchEditFocus",&Opt.ViOpt.SearchEditFocus,0, 0}, + {1, GeneralConfig::TYPE_INTEGER, NKeyDialog, L"EditHistory",&Opt.Dialogs.EditHistory,1, 0}, {1, GeneralConfig::TYPE_INTEGER, NKeyDialog, L"EditBlock",&Opt.Dialogs.EditBlock,0, 0}, {1, GeneralConfig::TYPE_INTEGER, NKeyDialog, L"AutoComplete",&Opt.Dialogs.AutoComplete,1, 0}, @@ -920,8 +923,15 @@ } } - Opt.ViOpt.ViewerIsWrap&=1; - Opt.ViOpt.ViewerWrap&=1; + Opt.ViOpt.ViewerIsWrap &= 1; + Opt.ViOpt.ViewerWrap &= 1; + if (!Opt.ViOpt.MaxLineSize) + Opt.ViOpt.MaxLineSize = 2048; + else if (Opt.ViOpt.MaxLineSize < 80) + Opt.ViOpt.MaxLineSize = 80; + else if (Opt.ViOpt.MaxLineSize > 16*1024) + Opt.ViOpt.MaxLineSize = 16*1024; + Opt.ViOpt.SearchEditFocus &= 1; // ������� �������� �������� ������������ ;-) if (Opt.strWordDiv.IsEmpty()) Index: config.hpp =================================================================== --- config.hpp (revision 6286) +++ config.hpp (working copy) @@ -314,6 +314,8 @@ int AnsiCodePageAsDefault; int ShowTitleBar; int SearchRegexp; + int MaxLineSize; // 80..16384, default=2048 + int SearchEditFocus; // auto-focus on edit text/hex window }; // "�����" |
|
новая версия выложена |
|
тестим - http://skirda-file.googlecode.com/files/Viewer-new.1.7z |
|
NewViewer2.diff (93,375 bytes)
Index: viewer.hpp =================================================================== --- viewer.hpp (revision 6286) +++ viewer.hpp (working copy) @@ -40,22 +40,13 @@ #include "config.hpp" #include "cache.hpp" -/* $ 10.07.2000 tran - ! modified MAXSCRY from 120 to 300 - on win200, with Console height FAR work, but trap on viewer... */ -#define MAXSCRY 300 +#define MAXSCRY 512 // 300 // 120 -/* $ 12.07.2000 SVS - - ��-�� �������� ���� ������ �� 0x800 ������ FAR - �� Alt-F7. �������� MAX_VIEWLINE �� 1024 (0x400) -*/ -#define MAX_VIEWLINE 0x800 // 0x400 -#define MAX_VIEWLINEB 0x80f // 0x40f +#define MAX_VIEWLINE (ViOpt.MaxLineSize+ 0) // 0x800 // 0x400 +#define MAX_VIEWLINEB (ViOpt.MaxLineSize+15) // 0x80f // 0x40f #define VIEWER_UNDO_COUNT 64 -enum {VIEW_UNWRAP=0,VIEW_WRAP=1, VIEW_WORDWRAP=2}; - class FileViewer; class KeyBar; @@ -65,7 +56,7 @@ __int64 nFilePos; __int64 nSelStart; __int64 nSelEnd; - int nbytes; + int linesize; bool bSelection; bool have_eol; }; @@ -76,12 +67,6 @@ __int64 UndoLeft; }; -enum SEARCH_FLAGS -{ - SEARCH_MODE2 = 0x00000001, - REVERSE_SEARCH = 0x00000002 -}; - enum SHOW_MODES { SHOW_RELOAD, @@ -95,9 +80,6 @@ friend class FileViewer; private: - - BitFlags SearchFlags; - struct ViewerOptions ViOpt; bool Signature; @@ -105,7 +87,7 @@ NamesList ViewNamesList; KeyBar *ViewKeyBar; - ViewerString *Strings[MAXSCRY+1]; + ViewerString **Strings; string strFileName; string strFullFileName; @@ -121,6 +103,8 @@ string strLastSearchStr; int LastSearchCase,LastSearchWholeWords,LastSearchReverse,LastSearchHex,LastSearchRegexp; + int LastSearchDirection; + __int64 StartSearchPos; struct ViewerMode VM; @@ -128,13 +112,12 @@ __int64 SecondPos; __int64 LastScrPos; __int64 FileSize; - __int64 LastSelPos; + __int64 LastSelectPos, LastSelectSize; __int64 LeftPos; __int64 LastPage; __int64 SelectPos,SelectSize; DWORD SelectFlags; - __int64 SelectPosOffSet; // ���������� �� �������� ������ ������� � ������� ����� int ShowStatusLine,HideCursor; string strTitle; @@ -165,9 +148,20 @@ char *vread_buffer; int vread_buffer_size; - wchar_t *Up_buffer; - int Up_buffer_size; + __int64 lcache_first; + __int64 lcache_last; + __int64 *lcache_lines; + int lcache_size; + int lcache_count; + int lcache_base; + bool lcache_ready; + int lcache_wrap; + int lcache_wwrap; + int lcache_width; + wchar_t *Search_buffer; + int Search_buffer_size; + ViewerString vString; unsigned char vgetc_buffer[32]; @@ -181,8 +175,9 @@ void ShowPage(int nMode); - void Up(); - int WrappedLength(wchar_t *str, int line_size); + void Up(int n); + void CacheLine(__int64 start, int length, bool have_eol); + int CacheFindUp(__int64 start); void ShowHex(); void ShowStatus(); @@ -195,17 +190,31 @@ void AdjustWidth(); void AdjustFilePos(); - void ReadString(ViewerString *pString, int MaxSize); - int CalcStrSize(const wchar_t *Str,int Length); + void ReadString(ViewerString *pString, int MaxSize, bool update_cache=true); + __int64 EndOfScreen( int line ); + __int64 BegOfScreen(); + void ChangeViewKeyBar(); + void Search(int Next,int FirstChar); - void ConvertToHex(char *SearchStr,int &SearchLength); + // + struct search_data; + // + int search_hex_forward( search_data* sd ); + int search_hex_backward( search_data* sd ); + int search_text_forward( search_data* sd ); + int search_text_backward( search_data* sd ); + int search_regex_forward( search_data* sd ); + int search_regex_backward( search_data* sd ); + int read_line(wchar_t *buf, wchar_t *tbuf, INT64 cpos, int adjust, INT64 &lpos, int &lsize); + int vread(wchar_t *Buf, int Count, wchar_t *Buf2 = nullptr); bool vseek(__int64 Offset, int Whence); __int64 vtell(); bool vgetc(wchar_t *ch); bool veof(); + wchar_t vgetc_prev(); void SetFileSize(); int GetStrBytesNum(const wchar_t *Str, int Length); @@ -283,5 +292,5 @@ int ProcessWrapMode(int newMode, bool isRedraw=TRUE); int ProcessTypeWrapMode(int newMode, bool isRedraw=TRUE); - void SearchTextTransform(UnicodeString &to, const wchar_t *from, bool hex2text); + void SearchTextTransform(UnicodeString &to, const wchar_t *from, bool hex2text, int &pos); }; Index: viewer.cpp =================================================================== --- viewer.cpp (revision 6286) +++ viewer.cpp (working copy) @@ -67,16 +67,17 @@ #include "wakeful.hpp" static void PR_ViewerSearchMsg(); -static void ViewerSearchMsg(const wchar_t *Name,int Percent); +static void ViewerSearchMsg(const wchar_t *name, int percent, int search_hex); -static int InitHex=FALSE,SearchHex=FALSE; +//static int InitHex=FALSE,SearchHex=FALSE; static int ViewerID=0; static int utf8_to_WideChar(const char *s, int nc, wchar_t *w1,wchar_t *w2, int wlen, int &tail); -#define REPLACE_CHAR 0xFFFD // Replacement +#define REPLACE_CHAR 0xFFFD // Replacement #define CONTINUE_CHAR 0x203A // Single Right-Pointing Angle Quotation Mark +#define BOM_CHAR 0xFEFF // Zero Length Space Viewer::Viewer(bool bQuickView, UINT aCodePage): ViOpt(Opt.ViOpt), @@ -85,10 +86,11 @@ { _OT(SysLog(L"[%p] Viewer::Viewer()", this)); - for (int i=0; i<=MAXSCRY; i++) + Strings = new ViewerString*[MAXSCRY+1]; + for (int i=0; i <= MAXSCRY; i++) { Strings[i] = new ViewerString(); - Strings[i]->lpData = new wchar_t[MAX_VIEWLINEB]; + memset(Strings[i], 0, sizeof(ViewerString)); } strLastSearchStr = strGlobalSearchString; @@ -97,19 +99,21 @@ LastSearchWholeWords=GlobalSearchWholeWords; LastSearchReverse=GlobalSearchReverse; LastSearchHex=GlobalSearchHex; + LastSearchDirection = GlobalSearchReverse ? -1 : +1; + StartSearchPos = 0; VM.CodePage=DefCodePage=aCodePage; // �������� ��� ����� VM.Wrap=Opt.ViOpt.ViewerIsWrap; VM.WordWrap=Opt.ViOpt.ViewerWrap; - VM.Hex=InitHex; + VM.Hex = FALSE; //InitHex; ViewKeyBar=nullptr; FilePos=0; LeftPos=0; SecondPos=0; FileSize=0; LastPage=0; - SelectPos=SelectSize=0; - LastSelPos=0; + SelectPos = 0; SelectSize = -1; + LastSelectPos = 0; LastSelectSize = -1; SetStatusMode(TRUE); HideCursor=TRUE; DeleteFolder=TRUE; @@ -123,7 +127,6 @@ CtrlObject->Plugins.CurViewer=this; OpenFailed=false; HostFileViewer=nullptr; - SelectPosOffSet=0; bVE_READ_Sent = false; Signature = false; @@ -132,8 +135,17 @@ vgetc_composite = L'\0'; vread_buffer = new char[vread_buffer_size = 8192]; - Up_buffer = new wchar_t[Up_buffer_size = 2 * (3*MAX_VIEWLINE + 2)]; + lcache_first = lcache_last = -1; + lcache_lines = new INT64[lcache_size = 8*1000]; + lcache_count = 0; + lcache_base = 0; + lcache_ready = false; + lcache_wrap = lcache_wwrap = lcache_width = -1; + + Search_buffer_size = 3 * (MAX_VIEWLINEB < 8000 ? 8000 : MAX_VIEWLINEB); + Search_buffer = new wchar_t[Search_buffer_size]; + memset(&vString, 0, sizeof(vString)); vString.lpData = new wchar_t[MAX_VIEWLINEB]; } @@ -169,7 +181,8 @@ } delete[] vString.lpData; - delete[] Up_buffer; + delete[] Search_buffer; + delete[] lcache_lines; delete[] vread_buffer; _tran(SysLog(L"[%p] Viewer::~Viewer, TempViewName=[%s]",this,TempViewName)); @@ -192,11 +205,13 @@ } } - for (int i=0; i<=MAXSCRY; i++) + for (int i=MAXSCRY; i >= 0; --i) { - delete [] Strings[i]->lpData; + if (Strings[i]->lpData) + delete[] Strings[i]->lpData; delete Strings[i]; } + delete[] Strings; if (!OpenFailed && bVE_READ_Sent) { @@ -216,7 +231,7 @@ Opt.ViOpt.ViewerIsWrap=VM.Wrap; Opt.ViOpt.ViewerWrap=VM.WordWrap; Opt.ViOpt.SearchRegexp=LastSearchRegexp; - InitHex=VM.Hex; + //InitHex=VM.Hex; } @@ -229,7 +244,7 @@ ViewFile.Close(); Reader.Clear(); - SelectSize = 0; // ������� �������� + SelectSize = -1; // ������� �������� strFileName = Name; if (Opt.OnlyEditorViewerUsed && !StrCmp(strFileName, L"-")) @@ -302,7 +317,7 @@ // �������� ������������� ��� ��� ���������� �� �� ������ ������� if (CachedCodePage && !IsCodePageSupported(CachedCodePage)) CachedCodePage = 0; - LastSelPos=FilePos=NewFilePos; + LastSelectPos=FilePos=NewFilePos; LeftPos=NewLeftPos; } else @@ -350,19 +365,13 @@ CodePageChangedByUser=TRUE; } - if (!IsUnicodeOrUtfCodePage(VM.CodePage)) - { - ViewFile.SetPointer(0, nullptr, FILE_BEGIN); - } + ViewFile.SetPointer(0, nullptr, FILE_BEGIN); } SetFileSize(); - if (FilePos>FileSize) + if (FilePos > FileSize) FilePos=0; -// if (ViOpt.AutoDetectTable && !TableChangedByUser) -// { -// } ChangeViewKeyBar(); AdjustWidth(); CtrlObject->Plugins.CurViewer=this; // HostFileViewer; @@ -379,12 +388,12 @@ DriveType = DRIVE_CDROM; switch (DriveType) //??? make it configurable { - case DRIVE_REMOVABLE: update_check_period = -1; break; // flash drive or floppy: never - case DRIVE_FIXED: update_check_period = +1; break; // hard disk: 1msec - case DRIVE_REMOTE: update_check_period = 1000; break; // network drive: 1sec - case DRIVE_CDROM: update_check_period = -1; break; // cd/dvd: never - case DRIVE_RAMDISK: update_check_period = +1; break; // ramdrive: 1msec - default: update_check_period = -1; break; // unknown: never + case DRIVE_REMOVABLE: update_check_period = -1; break; // flash drive or floppy: never + case DRIVE_FIXED: update_check_period = +1; break; // hard disk: 1 msec + case DRIVE_REMOTE: update_check_period = 500; break; // network drive: 0.5 sec + case DRIVE_CDROM: update_check_period = -1; break; // cd/dvd: never + case DRIVE_RAMDISK: update_check_period = +1; break; // ramdrive: 1 msec + default: update_check_period = -1; break; // unknown: never } return TRUE; @@ -428,8 +437,9 @@ SetCursorType(0,10); vseek(FilePos,SEEK_SET); + LastPage = 0; - if (!SelectSize) + if ( SelectSize < 0 ) SelectPos=FilePos; switch (nMode) @@ -471,7 +481,7 @@ } FilePos = Strings[0]->nFilePos; SecondPos = Strings[1]->nFilePos; - Strings[Y2-Y1]->nFilePos = Strings[Y2-Y1-1]->nFilePos + Strings[Y2-Y1-1]->nbytes; + Strings[Y2-Y1]->nFilePos = Strings[Y2-Y1-1]->nFilePos + Strings[Y2-Y1-1]->linesize; vseek(Strings[Y2-Y1]->nFilePos, SEEK_SET); ReadString(Strings[Y2-Y1],-1); break; @@ -487,21 +497,14 @@ if (StrLen > LeftPos) { - if (IsUnicodeOrUtfCodePage(VM.CodePage) && Signature && !I && !Strings[I]->nFilePos) - { - FS<<fmt::LeftAlign()<<fmt::Width(Width)<<fmt::Precision(Width)<<&Strings[I]->lpData[static_cast<size_t>(LeftPos+1)]; - } - else - { - FS<<fmt::LeftAlign()<<fmt::Width(Width)<<fmt::Precision(Width)<<&Strings[I]->lpData[static_cast<size_t>(LeftPos)]; - } + FS<<fmt::LeftAlign()<<fmt::Width(Width)<<fmt::Precision(Width)<<&Strings[I]->lpData[static_cast<size_t>(LeftPos)]; } else { FS<<fmt::Width(Width)<<L""; } - if (SelectSize && Strings[I]->bSelection) + if ( SelectSize >= 0 && Strings[I]->bSelection) { __int64 SelX1; @@ -532,7 +535,7 @@ if (LeftPos > Strings[I]->nSelEnd) Length = 0; - FS<<fmt::Precision(static_cast<int>(Length))<<&Strings[I]->lpData[static_cast<size_t>(SelX1+LeftPos+SelectPosOffSet)]; + FS<<fmt::Precision(static_cast<int>(Length))<<&Strings[I]->lpData[static_cast<size_t>(SelX1+LeftPos)]; } } @@ -571,6 +574,9 @@ bool bSelStartFound = false, bSelEndFound = false; __int64 HexLeftPos=((LeftPos>80-ObjWidth) ? Max(80-ObjWidth,0):LeftPos); + const wchar_t BorderLine[] = {BoxSymbols[BS_V1],L' ',0}; + int border_len = (int)wcslen(BorderLine); + for (EndFile=0,Y=Y1; Y<=Y2; Y++) { bSelStartFound = false; @@ -588,12 +594,9 @@ if (Y==Y1+1 && !veof()) SecondPos=vtell(); - INT64 Ptr=ViewFile.GetPointer(); - _snwprintf(OutStr,ARRAYSIZE(OutStr),L"%010I64X: ", Ptr); + int out_len = _snwprintf(OutStr,ARRAYSIZE(OutStr),L"%010I64X: ", vtell()); + SelEnd = SelStart = out_len; TextPos=0; - int HexStrStart = (int)wcslen(OutStr); - SelStart = HexStrStart; - SelEnd = SelStart; __int64 fpos = vtell(); if (fpos > SelectPos) @@ -602,103 +605,108 @@ if (fpos < SelectPos+SelectSize-1) bSelEndFound = true; - if (!SelectSize) + if ( SelectSize < 0 ) bSelStartFound = bSelEndFound = false; - const wchar_t BorderLine[]={BoxSymbols[BS_V1],L' ',0}; + unsigned char line[16+3]; + DWORD nr = 0; + DWORD nb = CP_UTF8 == VM.CodePage ? 16+3 : 16; + Reader.Read(line, nb, &nr); + if (nr > 16) + Reader.Unread(nr-16); - int out_len = (int)wcslen(OutStr); - int border_len = (int)wcslen(BorderLine); + LastPage = EndFile = (nr <= nb) && veof() ? 1 : 0; - if (IsUnicodeCodePage(VM.CodePage)) + if (nr <= 0) { - wchar_t line[8]; - int nr = vread(line, 8); - LastPage = EndFile = veof() ? 1 : 0; - if (nr <= 0) + *OutStr = L'\0'; + } + else + { + if (IsUnicodeCodePage(VM.CodePage)) { - *OutStr = L'\0'; - } - else - { - for (X=0; X<8; X++) + int be = VM.CodePage == CP_REVERSEBOM ? 1 : 0; + for (X=0; X<16; X += 2) { - if (SelectSize>0 && (SelectPos == fpos)) + if (SelectSize >= 0 && (SelectPos == fpos || SelectPos == fpos+1)) { + bool half = SelectPos != fpos; bSelStartFound = true; - SelStart = (int)wcslen(OutStr); - SelSize=SelectSize; + SelStart = out_len + (half ? 1+be : 0); + if ( 0 == (SelSize=SelectSize) ) + SelStart += (half ? be : 0) - 1; } - if (SelectSize>0 && (fpos == (SelectPos+SelectSize-1))) + if (SelectSize >= 0 && (fpos == SelectPos+SelectSize-1 || fpos+1 == SelectPos+SelectSize-1)) { + bool half = fpos == SelectPos+SelectSize-1; bSelEndFound = true; - SelEnd = (int)wcslen(OutStr)+3; - SelSize=SelectSize; + SelEnd = out_len+3 - (half ? 1+be : 0); + if ( 0 == (SelSize=SelectSize) ) + SelEnd = SelStart; } + else if ( SelectSize == 0 && (SelectPos == fpos || SelectPos == fpos+1) ) + { + bSelEndFound = true; + SelSize = 0; + SelEnd = SelStart; + } - if (X < nr) + if ((DWORD)X < nr-1) // full character { - unsigned char b1 = HIBYTE(line[X]), b2 = LOBYTE(line[X]); -#if 0 // !!! ��������� �������� !!! - if (VM.CodePage != CP_REVERSEBOM) // ��� ������ � ���� ���� - { // ������� �������� ������������� ��� - unsigned char t = b1; b1 = b2; b2 = t; - } -#endif - _snwprintf(OutStr+out_len, ARRAYSIZE(OutStr)-out_len, L"%02X%02X ", b1, b2); - TextStr[TextPos++] = line[X] ? line[X] : L' '; + unsigned ch = line[X+be] + (line[X+1-be] << 8); + _snwprintf(OutStr+out_len, ARRAYSIZE(OutStr)-out_len, L"%04X ", ch); + TextStr[TextPos++] = ch ? (wchar_t)ch : L' '; } - else + else if ((DWORD)X == nr-1) // half character only { + int o1 = 2 * (1 - be); + _snwprintf(OutStr+out_len+o1, ARRAYSIZE(OutStr)-out_len-o1, L"%02X", line[X]); + OutStr[out_len+2-o1] = OutStr[out_len+2-o1+1] = L'x'; + OutStr[out_len+4] = L' '; + TextStr[TextPos++] = REPLACE_CHAR; + } + else // no character + { wcscpy(OutStr+out_len, L" "); TextStr[TextPos++] = L' '; } out_len += 5; - if (X == 3) + if (X == 3*2) { wcscpy(OutStr+out_len, BorderLine); out_len += border_len; } - ++fpos; + fpos += 2; } } - } - else - { - unsigned char line[16+3]; - DWORD nr = 0; - DWORD nb = CP_UTF8 == VM.CodePage ? 16+3 : 16; - Reader.Read(line, nb, &nr); - if (nr > 16) - Reader.Unread(nr-16); - - LastPage = EndFile = (nr <= nb) && veof() ? 1 : 0; - - if (!nr) - { - *OutStr = L'\0'; - } else { - if (SelectSize) + if ( SelectSize >= 0 ) { if (SelectPos >= fpos && SelectPos < fpos+16) { int off = (int)(SelectPos - fpos); bSelStartFound = true; SelStart = out_len + 3*off + (off < 8 ? 0 : border_len); - SelSize = SelectSize; + if ( 0 == (SelSize=SelectSize) ) + --SelStart; } __int64 selectEnd = SelectPos + SelectSize - 1; if (selectEnd >= fpos && selectEnd < fpos+16) { int off = (int)(selectEnd - fpos); bSelEndFound = true; - SelEnd = out_len + 3*off + (off < 8 ? 0 : border_len) + 1; - SelSize = SelectSize; + SelEnd = (0 == (SelSize=SelectSize) ? SelStart : out_len + 3*off + (off < 8 ? 0 : border_len) + 1); } + else if ( SelectSize == 0 && SelectPos == fpos ) + { + bSelEndFound = true; + SelSize = 0; + SelEnd = SelStart; + } } + for (X=0; X<16; X++) { int off = out_len + 3*X + (X < 8 ? 0 : border_len); @@ -712,6 +720,7 @@ if (CP_UTF8 != VM.CodePage && X < (int)nr && line[X]) MultiByteToWideChar(VM.CodePage, 0, (LPCSTR)line+X, 1, TextStr+X, 1); } + out_len += 3*16 + border_len; if (CP_UTF8 == VM.CodePage) { @@ -730,7 +739,7 @@ first = false; TextStr[ib++] = w1[iw] ? w1[iw] : L' '; } - int clen = WideCharToMultiByte(CP_UTF8, 0, w2+iw, 1, nullptr, 0, nullptr, nullptr); + int clen = WideCharToMultiByte(CP_UTF8, 0, w2+iw, 1, NULL,0, NULL,NULL); while (--clen > 0 && ib < 16) TextStr[ib++] = CONTINUE_CHAR; ++iw; @@ -740,14 +749,14 @@ } } - TextStr[TextPos]=0; - wcscat(TextStr,L" "); + TextStr[TextPos] = L' '; + TextStr[TextPos+1] = L'\0'; - if ((SelEnd <= SelStart) && bSelStartFound) - SelEnd = (int)wcslen(OutStr)-2; + if ((SelEnd <= SelStart) && bSelStartFound && bSelEndFound && SelectSize > 0 ) + SelEnd = out_len-2; - wcscat(OutStr,L" "); - wcscat(OutStr,TextStr); + OutStr[out_len] = L' '; + wcscpy(OutStr+out_len+1, TextStr); if (StrLength(OutStr)>HexLeftPos) { @@ -789,7 +798,7 @@ { 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); + ScrollBarEx(X2+(m_bQuickView?1:0),Y1,Y2-Y1+1,LastPage?Top?Total:0:Top,Total); } } } @@ -837,6 +846,15 @@ return L'\0' == ch || IsSpace(ch); } +static bool is_word_div ( const wchar_t ch ) +{ + static const wchar_t spaces[] = { L' ', L'\t', L'\n', L'\r', BOM_CHAR, REPLACE_CHAR, L'\0' }; + return ( !ch + || nullptr != wcschr(spaces, ch) + || nullptr != wcschr(Opt.strWordDiv, ch) + ); +} + static inline int wrapped_char( const wchar_t ch ) { static const wchar_t wrapped_chars[] = L",;>)"; // word-wrap enabled after it @@ -849,18 +867,31 @@ return -1; } -void Viewer::ReadString(ViewerString *pString, int MaxSize) +static inline int getCharSize( UINT cp ) { + if ( CP_UTF8 == cp ) + return -1; + else if ( CP_UNICODE == cp || CP_REVERSEBOM == cp ) + return +2; + else + return +1; +} + +void Viewer::ReadString( ViewerString *pString, int MaxSize, bool update_cache ) +{ AdjustWidth(); int OutPtr = 0, nTab = 0, wrap_out = -1; wchar_t ch, eol_char = L'\0'; - __int64 fpos, sel_end, wrap_pos = -1; + INT64 fpos=0, fpos1, sel_end, wrap_pos = -1; bool skip_space = false; + if ( !pString->lpData ) + pString->lpData = new wchar_t[MAX_VIEWLINEB]; + if (VM.Hex) { - vseek(IsUnicodeCodePage(VM.CodePage) ? 8 : 16, FILE_CURRENT); + vseek(16, FILE_CURRENT); pString->lpData[OutPtr] = L'\0'; LastPage = veof(); return; @@ -869,10 +900,12 @@ bool bSelStartFound = false, bSelEndFound = false; pString->bSelection = false; sel_end = SelectPos + SelectSize; - fpos = vtell(); + fpos1 = vtell(); for (;;) { + fpos = fpos1; + if (OutPtr >= MAX_VIEWLINE) break; @@ -880,27 +913,31 @@ ch = L' '; else { - fpos = vtell(); if (!MaxSize-- || !vgetc(&ch)) break; } + fpos1 = vtell(); - if (SelectSize > 0) + if (SelectSize >= 0) { - if (fpos == SelectPos) + if (fpos == SelectPos || (fpos < SelectPos && fpos1 > SelectPos)) { pString->nSelStart = OutPtr; bSelStartFound = true; } - if (fpos == sel_end) + if (fpos == sel_end || (fpos < sel_end && fpos1 > sel_end)) { - pString->nSelEnd = OutPtr; + pString->nSelEnd = OutPtr + (fpos < sel_end ? 1 : 0); bSelEndFound = true; } } - if (L'\t' == ch) + if (!fpos && BOM_CHAR == ch) { + continue; // skip BOM + } + else if (L'\t' == ch) + { nTab = ViOpt.TabSize - (OutPtr % ViOpt.TabSize); continue; } @@ -913,7 +950,7 @@ pString->lpData[OutPtr++] = ch ? ch : L' '; if (!VM.Wrap) continue; - + if (OutPtr >= Width) { if (VM.WordWrap && wrap_out > 0) @@ -965,9 +1002,12 @@ pString->have_eol = (eol_char != L'\0'); pString->lpData[(int)OutPtr]=0; - pString->nbytes = (int)(vtell() - pString->nFilePos); + pString->linesize = (int)(vtell() - pString->nFilePos); - if (SelectSize > 0 && OutPtr > 0) + if ( update_cache ) + CacheLine(pString->nFilePos, pString->linesize, pString->have_eol); + + if (SelectSize >= 0 && OutPtr > 0) { if (!bSelStartFound && pString->nFilePos >= SelectPos && pString->nFilePos <= sel_end) { @@ -987,8 +1027,86 @@ if (!eol_char && veof()) LastPage = 1; +} + + +__int64 Viewer::EndOfScreen( int line ) +{ + __int64 pos; + + if (!VM.Hex) + { + pos = Strings[Y2-Y1+line]->nFilePos + Strings[Y2-Y1+line]->linesize; + if ( !line && !VM.Wrap && Strings[Y2-Y1]->linesize > 0 ) + { + vseek(Strings[Y1-Y2]->nFilePos, SEEK_SET); + int col = 0, rmargin = (int)LeftPos + Width; + wchar_t ch; + for (;;) + { + if ( !vgetc(&ch) ) + break; + if ( ch == L'\n' || ch == L'\r' ) + break; + if ( ch == L'\t' ) + col += ViOpt.TabSize - (col % ViOpt.TabSize); + else + ++col; + if ( col >= rmargin ) + { + pos = vtell(); + break; + } + } + } + } + else + pos = FilePos + 16 * (Y2-Y1+1+line); + + if (pos < 0) + pos = 0; + else if (pos > FileSize) + pos = FileSize; + + return pos; } + +__int64 Viewer::BegOfScreen() +{ + __int64 pos = FilePos, prev_pos; + + if (!VM.Hex && !VM.Wrap && LeftPos > 0) + { + vseek(FilePos, SEEK_SET); + int col = 0; + wchar_t ch; + pos = -1; + for (;;) + { + prev_pos = vtell(); + if ( !vgetc(&ch) ) + break; + if ( ch == L'\n' || ch == L'\r' ) + { + pos = Strings[1]->nFilePos; + break; + } + if ( ch == L'\t' ) + col += ViOpt.TabSize - (col % ViOpt.TabSize); + else + ++col; + if ( col > LeftPos ) //!! ������ �������� ����� ������ + break; //!! ��� LeftPos=1 �� ���� 2 ������� + } + if ( pos < 0 ) + pos = (col > LeftPos ? prev_pos : vtell()); + } + + return pos; +} + + __int64 Viewer::VMProcess(int OpCode,void *vParam,__int64 iParam) { switch (OpCode) @@ -996,7 +1114,7 @@ case MCODE_C_EMPTY: return (__int64)!FileSize; case MCODE_C_SELECTED: - return (__int64)(SelectSize?TRUE:FALSE); + return (__int64)(SelectSize >= 0 ?TRUE:FALSE); case MCODE_C_EOF: return (__int64)(LastPage || !ViewFile.Opened()); case MCODE_C_BOF: @@ -1030,7 +1148,7 @@ */ if (!ViOpt.PersistentBlocks && Key!=KEY_IDLE && Key!=KEY_NONE && !(Key==KEY_CTRLINS||Key==KEY_CTRLNUMPAD0) && Key!=KEY_CTRLC) - SelectSize=0; + SelectSize = -1; if (!InternalKey && !LastKeyUndo && (FilePos!=UndoData[0].UndoAddr || LeftPos!=UndoData[0].UndoLeft)) { @@ -1055,7 +1173,6 @@ { FilePos=BMSavePos.FilePos[Pos]; LeftPos=BMSavePos.LeftPos[Pos]; -// LastSelPos=FilePos; Show(); } @@ -1082,25 +1199,20 @@ } case KEY_CTRLU: { -// if (SelectSize) - { - SelectSize = 0; - Show(); - } + SelectSize = -1; + Show(); return TRUE; } case KEY_CTRLC: case KEY_CTRLINS: case KEY_CTRLNUMPAD0: { - if (SelectSize && ViewFile.Opened()) + if (SelectSize >= 0 && ViewFile.Opened()) { - wchar_t *SelData; - size_t DataSize = (size_t)SelectSize+(IsUnicodeCodePage(VM.CodePage)?sizeof(wchar_t):1); - __int64 CurFilePos=vtell(); - - if ((SelData=(wchar_t*)xf_malloc(DataSize*sizeof(wchar_t))) ) + wchar_t *SelData = (wchar_t*)xf_malloc((size_t)SelectSize+1); + if ( SelData ) { - wmemset(SelData, 0, DataSize); + __int64 CurFilePos=vtell(); + wmemset(SelData, 0, (size_t)SelectSize+1); vseek(SelectPos,SEEK_SET); vread(SelData, (int)SelectSize); CopyToClipboard(SelData); @@ -1108,7 +1220,6 @@ vseek(CurFilePos,SEEK_SET); } } - return TRUE; } // �����/����� �������� @@ -1145,6 +1256,8 @@ Reader.Clear(); // ���� ���� �� ��� ����? ViewFile.FlushBuffers(); + vseek(0, SEEK_CUR); // reset vgetc state + lcache_ready = false; // reset start-lines cache if (FilePos>FileSize) { @@ -1251,19 +1364,16 @@ } case KEY_SHIFTF2: { - LastPage = 0; ProcessTypeWrapMode(!VM.WordWrap); return TRUE; } case KEY_F2: { - LastPage = 0; ProcessWrapMode(!VM.Wrap); return TRUE; } case KEY_F4: { - LastPage = 0; ProcessHexMode(!VM.Hex); return TRUE; } @@ -1280,23 +1390,13 @@ } case KEY_ALTF7: { - SearchFlags.Set(REVERSE_SEARCH); - Search(1,0); - SearchFlags.Clear(REVERSE_SEARCH); + Search(-1,0); return TRUE; } case KEY_F8: { - LastPage = 0; - if (IsUnicodeCodePage(VM.CodePage)) - { - FilePos*=2; - SetFileSize(); - SelectPos = 0; - SelectSize = 0; - } - VM.CodePage = VM.CodePage==GetOEMCP() ? GetACP() : GetOEMCP(); + lcache_ready = false; ChangeViewKeyBar(); Show(); CodePageChangedByUser=TRUE; @@ -1304,12 +1404,12 @@ } case KEY_SHIFTF8: { - LastPage = 0; UINT nCodePage = SelectCodePage(VM.CodePage, true, true, false, true); + lcache_ready = false; - if (nCodePage!=(UINT)-1) + if (nCodePage != static_cast<UINT>(-1)) { - if (nCodePage == (WORD)(CP_AUTODETECT & 0xffff)) + if (nCodePage == (CP_AUTODETECT & 0xffff)) { __int64 fpos = vtell(); bool detect = GetFileFormat(ViewFile,nCodePage,&Signature,true) && IsCodePageSupported(nCodePage); @@ -1318,20 +1418,6 @@ nCodePage = Opt.ViOpt.AnsiCodePageAsDefault ? GetACP() : GetOEMCP(); } CodePageChangedByUser=TRUE; - - if (IsUnicodeCodePage(VM.CodePage) && !IsUnicodeCodePage(nCodePage)) - { - FilePos*=2; - SelectPos = 0; - SelectSize = 0; - } - else if (!IsUnicodeCodePage(VM.CodePage) && IsUnicodeCodePage(nCodePage)) - { - FilePos=(FilePos+(FilePos&1))/2; //???? - SelectPos = 0; - SelectSize = 0; - } - VM.CodePage=nCodePage; SetFileSize(); ChangeViewKeyBar(); @@ -1402,11 +1488,10 @@ { if (FilePos>0 && ViewFile.Opened()) { - Up(); // LastPage = 0 + Up(1); // LastPage = 0 if (VM.Hex) { - //FilePos&=~(IsUnicodeCodePage(VM.CodePage) ? 0x7:0xf); Show(); } else @@ -1414,7 +1499,7 @@ ShowPage(SHOW_UP); ViewerString *end = Strings[Y2-Y1]; LastPage = end->nFilePos >= FileSize || - (!end->have_eol && end->nFilePos + end->nbytes >= FileSize); + (!end->have_eol && end->nFilePos + end->linesize >= FileSize); } } @@ -1439,9 +1524,7 @@ { if (ViewFile.Opened()) { - for (int i=Y1; i<Y2; i++) - Up(); - + Up(Y2-Y1); Show(); } @@ -1452,25 +1535,25 @@ if (LastPage || !ViewFile.Opened()) return TRUE; - if (VM.Hex) - FilePos += (IsUnicodeCodePage(VM.CodePage) ? 8 : 16) * (Y2-Y1); - else - FilePos = Strings[Y2-Y1]->nFilePos; + FilePos = EndOfScreen(-1); // start of last screen line if (Key == KEY_CTRLDOWN) { - vseek(FilePos, SEEK_SET); + vseek(vString.nFilePos = FilePos, SEEK_SET); for (int i=Y1; i<=Y2; i++) - ReadString(&vString,-1); + { + ReadString(&vString,-1); + vString.nFilePos += vString.linesize; + } if (LastPage) - { - InternalKey++; - ProcessKey(KEY_CTRLPGDN); - InternalKey--; - return TRUE; + { + InternalKey++; + ProcessKey(KEY_CTRLPGDN); + InternalKey--; + return TRUE; + } } - } Show(); return TRUE; @@ -1504,17 +1587,11 @@ { if (VM.Hex) { - FilePos--; - - if (FilePos<0) - FilePos=0; + FilePos = FilePos > 0 ? FilePos-1 : 0; } else { - LeftPos-=20; - - if (LeftPos<0) - LeftPos=0; + LeftPos = LeftPos > 20 ? LeftPos-20 : 0; } Show(); @@ -1528,10 +1605,7 @@ { if (VM.Hex) { - FilePos++; - - if (FilePos >= FileSize) - FilePos=FileSize-1; //?? + FilePos = FilePos < FileSize-1 ? FilePos+1 : FileSize-1; } else if (!VM.Wrap) { @@ -1592,7 +1666,6 @@ if (ViewFile.Opened()) { FilePos=0; - LastPage = 0; Show(); } @@ -1614,32 +1687,33 @@ ��������� End (� ������) �� ����� ������ �������� �� ��������� Down. */ - unsigned int max_counter=Y2-Y1; + int max_counter = Y2 - Y1; if (VM.Hex) { vseek(0,SEEK_END); FilePos = vtell(); - int line_chars = IsUnicodeCodePage(VM.CodePage) ? 8 : 16; - if ((FilePos % line_chars) == 0) - FilePos -= line_chars * (Y2 - Y1 + 1); + if ((FilePos % 16) == 0) + FilePos -= 16 * (Y2 - Y1 + 1); else - FilePos -= (FilePos % line_chars) + line_chars * (Y2 - Y1); + FilePos -= (FilePos % 16) + 16 * (Y2 - Y1); if (FilePos < 0) FilePos = 0; } else { - vseek(-1,SEEK_END); - WCHAR LastSym=0; + int ch_size = getCharSize(VM.CodePage); + wchar_t LastSym = L'\0'; - if (vgetc(&LastSym) && LastSym!=L'\n' && LastSym!=L'\r') + vseek(0, SEEK_END); + FilePos = vtell() - 1; + FilePos -= FilePos % ch_size; + vseek(FilePos, SEEK_SET); + if (vgetc(&LastSym) && LastSym != L'\n' && LastSym != L'\r') ++max_counter; FilePos=vtell(); - - for (int i=0; static_cast<unsigned int>(i)<max_counter; i++) - Up(); + Up(max_counter); } Show(); @@ -1688,7 +1762,7 @@ { while (IsMouseButtonPressed()) { -// _SVS(SysLog(L"Viewer/ KEY_DOWN= %i, %i",FilePos,FileSize)); + //_SVS(SysLog(L"Viewer/ KEY_DOWN= %i, %i",FilePos,FileSize)); ProcessKey(KEY_DOWN); } } @@ -1719,7 +1793,7 @@ else Perc=ToPercent64(FilePos,FileSize); -//_SVS(SysLog(L"Viewer/ ToPercent()=%i, %I64d, %I64d, Mouse=[%d:%d]",Perc,FilePos,FileSize,MsX,MsY)); + //_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) @@ -1796,140 +1870,270 @@ return TRUE; } -void Viewer::Up() + +void Viewer::CacheLine( __int64 start, int length, bool have_eol ) { - if (!ViewFile.Opened()) + assert(start >= 0 && length >= 0); + if (!length) // empty lines beyond EOF return; - LastPage = 0; + if ( lcache_ready + && (lcache_wrap != VM.Wrap || lcache_wwrap != VM.WordWrap || lcache_width != Width) + ){ + lcache_ready = false; + } - if (FilePos <= 0) - return; - - if (VM.Hex) + if (!lcache_ready || start > lcache_last || start+length < lcache_first) { - FilePos -= IsUnicodeCodePage(VM.CodePage) ? 8 : 16; - if (FilePos < 0) - FilePos = 0; - return; - } + lcache_first = start; + lcache_last = start + length; - int Skipped = 0, I = -1, BufSize = MAX_VIEWLINE + 2; - wchar_t *Buf = Up_buffer, *tBuf = Up_buffer, *tBuf2 = nullptr; + lcache_count = 2; + lcache_base = 0; + lcache_lines[0] = (have_eol ? -start : +start); + lcache_lines[1] = start + length; - if (!VM.Hex && VM.CodePage == CP_UTF8) - { - BufSize = Up_buffer_size / 2; // = 3*MAXLINE + 2; - tBuf = tBuf2 = Up_buffer + BufSize; + lcache_wrap = VM.Wrap; lcache_wwrap = VM.WordWrap; lcache_width = Width; + lcache_ready = true; } - - if (FilePos < (__int64)BufSize) - BufSize = (int)FilePos; - - if (BufSize >= 512) // first try to find newline in first 256 bytes + else if (start == lcache_last) { - vseek(FilePos-256, SEEK_SET); - int nr = vread(Buf, 256, tBuf2); - - if (nr > 0 && Buf[nr-1] == L'\n') + int i = (lcache_base + lcache_count - 1) % lcache_size; + lcache_lines[i] = (have_eol ? -start : +start); + i = (i + 1) % lcache_size; + lcache_lines[i] = lcache_last = start + length; + if (lcache_count < lcache_size) + ++lcache_count; + else { - --nr; ++Skipped; + lcache_base = (lcache_base + 1) % lcache_size; // ++start + lcache_first = _abs64(lcache_lines[lcache_base]); } - if (nr > 0 && Buf[nr-1] == L'\r') + } + else if (start+length == lcache_first) + { + lcache_base = (lcache_base + lcache_size - 1) % lcache_size; // --start + lcache_lines[lcache_base] = (have_eol ? -start : +start); + lcache_first = start; + if (lcache_count < lcache_size) + ++lcache_count; + else { - --nr; ++Skipped; + int i = (lcache_base + lcache_size - 1) % lcache_size; // i = start - 1 + lcache_last = _abs64(lcache_lines[i]); } + } + else + { +#if defined(_DEBUG) && 1 // it is legal case if file changed... + assert(start >= lcache_first && start+length <= lcache_last); + int i = CacheFindUp(start+length); + assert(i >= 0 && _abs64(lcache_lines[i]) == start); +#endif + lcache_first = start; + lcache_last = start + length; - for (I = nr-1; I >= 0; I--) - { - if (Buf[I] == L'\n' || Buf[I] == L'\r') - { - BufSize = nr; - break; - } - } + lcache_count = 2; + lcache_base = 0; + lcache_lines[0] = (have_eol ? -start : +start); + lcache_lines[1] = start + length; } +} - if (I < 0) // full portion read +int Viewer::CacheFindUp( __int64 start ) +{ + if ( lcache_ready + && (lcache_wrap != VM.Wrap || lcache_wwrap != VM.WordWrap || lcache_width != Width) + ){ + lcache_ready = false; + } + if ( !lcache_ready || start <= lcache_first || start > lcache_last ) + return -1; + + int i, j, i1 = 0, i2 = lcache_count - 1; + for (;;) { - vseek(FilePos - BufSize, SEEK_SET); - BufSize = vread(Buf, BufSize, tBuf2); - Skipped=0; + if ( i1+1 >= i2 ) + return (lcache_base + i1) % lcache_size; - if (BufSize > 0 && Buf[BufSize-1]==L'\n') - { - --BufSize; ++Skipped; - } - if (BufSize > 0 && Buf[BufSize-1] == L'\r') - { - --BufSize; ++Skipped; - } - - int I0 = BufSize > MAX_VIEWLINE ? BufSize - MAX_VIEWLINE : 0; - for (I = BufSize-1; I >= I0; I--) - { - if (Buf[I] == L'\n' || Buf[I] == L'\r') - break; - } + i = (i1 + i2) / 2; + j = (lcache_base + i) % lcache_size; + if (_abs64(lcache_lines[j]) < start) + i1 = i; + else + i2 = i; } +} - if (!VM.Wrap) +void Viewer::Up( int nlines ) +{ + assert( nlines > 0 ); + + if (!ViewFile.Opened()) + return; + + LastPage = 0; + + if (FilePos <= 0) + return; + + if (VM.Hex) { - FilePos -= GetStrBytesNum(tBuf + (I+1), BufSize-(I+1)) + Skipped; + FilePos = FilePos > 16*nlines ? FilePos-16*nlines : 0; + return; } - else + + __int64 fpos, fpos1; + + int i = CacheFindUp(fpos = FilePos); + if ( i >= 0 ) { - wchar_t *line = tBuf + I+1; - int len, line_size = BufSize - (I+1); for (;;) { - len = WrappedLength(line, line_size); - if ( len >= line_size ) + fpos = _abs64(lcache_lines[i]); + if (--nlines == 0) + { + FilePos = fpos; + return; + } + if (i == lcache_base) break; - line += len; - line_size -= len; + i = (i + lcache_size - 1) % lcache_size; } - FilePos -= GetStrBytesNum(line, line_size + Skipped); } - return; -} -int Viewer::WrappedLength(wchar_t *str, int line_size) -{ - int width = 0, off = 0, wrap_pos = -1, wrap_ch, tab_size = ViOpt.TabSize; - bool wwrap = VM.Wrap && VM.WordWrap; + static const int portion_size = 256; + static const int max_backward = 32*1024; - for (;;) + union { + char c1[portion_size]; + wchar_t c2[portion_size/(int)sizeof(wchar_t)]; + } buff; + + int j, buff_size, nr, ch_size = getCharSize(VM.CodePage); + int len[max_backward/40]; // suppose minimum line with is 80 chars... + + while ( nlines > 0 ) { - if (off >= line_size) - return off; + if ( fpos <= 0 ) + { + FilePos = 0; + return; + } - wchar_t ch = str[off++]; - width += L'\t' != ch ? 1 : tab_size - width % tab_size; + fpos1 = fpos; - if (width >= Width) + // backward CR-LF search + // + for ( j = 0; j < max_backward/portion_size; ++j ) { - if (!wwrap || wrap_pos <= 0) - return off; - while (wrap_pos < line_size && is_space_or_nul(str[wrap_pos])) - ++wrap_pos; - return wrap_pos; + buff_size = (fpos > (__int64)portion_size ? portion_size : (int)fpos); + fpos -= buff_size; + vseek(fpos, SEEK_SET); + + if ( ch_size <= 1 ) + { + DWORD nread = 0; + Reader.Read(buff.c1, static_cast<DWORD>(buff_size), &nread); + if ((nr = (int)nread) != buff_size) + { + return; //??? error handling + } + if ( 0 == j ) + { + if ( nr > 0 && '\n' == buff.c1[nr-1] ) + { + --nr; + } + if ( nr > 0 && '\r' == buff.c1[nr-1] ) + { + --nr; + } + } + for ( i = nr-1; i >= 0; --i ) + { + if ( '\n' == buff.c1[i] || '\r' == buff.c1[i] ) + break; + } + if ( i >= 0 ) + { + fpos += i + 1; + break; + } + } + else + { + nr = vread(buff.c2, buff_size); + if ( nr != buff_size / ch_size ) + { + return; //??? error handling + } + if ( 0 == j ) + { + if ( nr > 0 && L'\n' == buff.c2[nr-1] ) + { + --nr; + } + if ( nr > 0 && L'\r' == buff.c2[nr-1] ) + { + --nr; + } + } + for ( i = nr-1; i >= 0; --i ) + { + if ( L'\n' == buff.c2[i] || L'\r' == buff.c2[i] ) + break; + } + if ( i >= 0 ) + { + fpos += ch_size * (i + 1); + break; + } + } } - if (!wwrap) - continue; + // split read portion + // + vseek(vString.nFilePos = fpos, SEEK_SET); + for (i = 0; i < (int)ARRAYSIZE(len); ++i) + { + ReadString(&vString, -1, false); + len[i] = (vString.have_eol ? -1 : +1) * vString.linesize; + if ((vString.nFilePos += vString.linesize) >= fpos1) + { + fpos1 = vString.nFilePos; + break; + } + } + assert(i < (int)ARRAYSIZE(len)); + if (i >= (int)ARRAYSIZE(len)) + --i; - if ((wrap_ch = wrapped_char(ch)) >= 0) - wrap_pos = off - 1 + wrap_ch; + while ( i >= 0 ) + { + int l = len[i--]; + bool eol = false; + if (l < 0) + { + eol = true; + l = -l; + } + fpos1 -= l; + CacheLine(fpos1, l, eol); + if (--nlines == 0) + FilePos = fpos1; + } } } -int Viewer::GetStrBytesNum(const wchar_t *Str, int Length) + +int Viewer::GetStrBytesNum( const wchar_t *Str, int Length ) { - if (IsUnicodeCodePage(VM.CodePage)) - return Length; + int ch_size = getCharSize(VM.CodePage); + if (ch_size > 0) + return Length * ch_size; else - return WideCharToMultiByte(VM.CodePage, 0, Str, Length, nullptr, 0, nullptr, nullptr); + return WideCharToMultiByte(VM.CodePage,0, Str,Length, nullptr,0, nullptr,nullptr); } void Viewer::SetViewKeyBar(KeyBar *ViewKeyBar) @@ -1938,7 +2142,6 @@ ChangeViewKeyBar(); } - void Viewer::ChangeViewKeyBar() { if (ViewKeyBar) @@ -1971,6 +2174,7 @@ CtrlObject->Plugins.CurViewer=this; //HostFileViewer; } + enum SEARCHDLG { SD_DOUBLEBOX, @@ -1991,9 +2195,18 @@ enum { - DM_SDSETVISIBILITY = DM_USER+1, + DM_SDSETVISIBILITY = DM_USER + 1, + DM_SDREXVISIBILITY = DM_USER + 2 }; +struct MyDialogData +{ + Viewer *viewer; + bool edit_autofocus; + bool hex_mode; + bool recursive; +}; + INT_PTR WINAPI ViewerSearchDlgProc(HANDLE hDlg,int Msg,int Param1,void* Param2) { switch (Msg) @@ -2010,42 +2223,133 @@ SendDlgMessage(hDlg,DM_SHOWITEM,SD_EDIT_TEXT,ToPtr(!Param1)); SendDlgMessage(hDlg,DM_SHOWITEM,SD_EDIT_HEX,ToPtr(Param1)); SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_CASE,ToPtr(!Param1)); - SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_WORDS,ToPtr(!Param1)); - //SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_REGEXP,!Param1); + int re = SendDlgMessage(hDlg, DM_GETCHECK,SD_CHECKBOX_REGEXP,0) == BSTATE_CHECKED; + int ww = !Param1 && !re; + SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_WORDS,ToPtr(ww)); + SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_REGEXP,ToPtr(!Param1)); + SendDlgMessage(hDlg, DM_SDREXVISIBILITY, re && !Param1, 0); return TRUE; } + case DM_SDREXVISIBILITY: + { + int show = 1; + if ( Param1 ) + { + int tlen = (int)SendDlgMessage(hDlg, DM_GETTEXTPTR, SD_EDIT_TEXT, 0); + show = 0; + if ( tlen > 0 ) + { + RegExp re; + wchar_t t[128], *tmp = t; + if (tlen > (int)ARRAYSIZE(t)) + tmp = new wchar_t[tlen]; + SendDlgMessage(hDlg, DM_GETTEXTPTR, SD_EDIT_TEXT, tmp); + string sre = tmp; + InsertRegexpQuote(sre); + show = re.Compile(sre.CPtr(), OP_PERLSTYLE); + if (tmp != t) + delete[] tmp;; + } + } + SendDlgMessage(hDlg, DM_ENABLE, SD_TEXT_SEARCH, ToPtr(show)); + SendDlgMessage(hDlg, DM_ENABLE, SD_BUTTON_OK, ToPtr(show)); + return TRUE; + } + case DN_KILLFOCUS: + { + if ( SD_EDIT_TEXT == Param1 || SD_EDIT_HEX == Param1 ) + { + MyDialogData *my = (MyDialogData *)SendDlgMessage(hDlg, DM_GETITEMDATA, SD_EDIT_TEXT, 0); + my->hex_mode = (SD_EDIT_HEX == Param1); + } + break; + } case DN_BTNCLICK: { + bool need_focus = false; + MyDialogData *my = (MyDialogData *)SendDlgMessage(hDlg, DM_GETITEMDATA, SD_EDIT_TEXT, 0); + int cradio = (my->hex_mode ? SD_RADIO_HEX : SD_RADIO_TEXT); + if ((Param1 == SD_RADIO_TEXT || Param1 == SD_RADIO_HEX) && Param2) { - SendDlgMessage(hDlg, DM_ENABLEREDRAW, FALSE, 0); - Viewer *viewer = (Viewer *)SendDlgMessage(hDlg, DM_GETITEMDATA, SD_EDIT_TEXT, 0); + need_focus = true; + if ( Param1 != cradio) + { + bool new_hex = (Param1 == SD_RADIO_HEX); - int sd_dst = Param1 == SD_RADIO_HEX ? SD_EDIT_HEX : SD_EDIT_TEXT; - int sd_src = Param1 == SD_RADIO_TEXT ? SD_EDIT_HEX : SD_EDIT_TEXT; + SendDlgMessage(hDlg, DM_ENABLEREDRAW, FALSE, 0); - const wchar_t *ps = (const wchar_t *)SendDlgMessage(hDlg, DM_GETCONSTTEXTPTR, sd_src, 0); - string strTo; - viewer->SearchTextTransform(strTo, ps, Param1 == SD_RADIO_TEXT); + int sd_dst = new_hex ? SD_EDIT_HEX : SD_EDIT_TEXT; + int sd_src = new_hex ? SD_EDIT_TEXT : SD_EDIT_HEX; - SendDlgMessage(hDlg, DM_SETTEXTPTR, sd_dst, const_cast<wchar_t*>(strTo.CPtr())); - SendDlgMessage(hDlg, DM_SDSETVISIBILITY, Param1 == SD_RADIO_HEX, 0); + EditorSetPosition esp; + esp.CurPos = -1; + SendDlgMessage(hDlg, DM_GETEDITPOSITION, sd_src, &esp); + const wchar_t *ps = (const wchar_t *)SendDlgMessage(hDlg, DM_GETCONSTTEXTPTR, sd_src, 0); + string strTo; + my->viewer->SearchTextTransform(strTo, ps, !new_hex, esp.CurPos); - if (!strTo.IsEmpty()) - { - int changed = (int)SendDlgMessage(hDlg, DM_EDITUNCHANGEDFLAG, sd_src, ToPtr(-1)); - SendDlgMessage(hDlg, DM_EDITUNCHANGEDFLAG, sd_dst, ToPtr(changed)); + SendDlgMessage(hDlg, DM_SETTEXTPTR, sd_dst, ToPtr((INT_PTR)strTo.CPtr())); + SendDlgMessage(hDlg, DM_SDSETVISIBILITY, new_hex, 0); + if (esp.CurPos >= 0) + { + int p = esp.CurPos; + if (SendDlgMessage(hDlg, DM_GETEDITPOSITION, sd_dst, &esp)) + { + esp.CurPos = esp.CurTabPos = p; + esp.LeftPos = 0; + SendDlgMessage(hDlg, DM_SETEDITPOSITION, sd_dst, &esp); + } + } + + if (!strTo.IsEmpty()) + { + int changed = (int)SendDlgMessage(hDlg, DM_EDITUNCHANGEDFLAG, sd_src, ToPtr(-1)); + SendDlgMessage(hDlg, DM_EDITUNCHANGEDFLAG, sd_dst, ToPtr(changed)); + } + + SendDlgMessage(hDlg,DM_ENABLEREDRAW,TRUE,0); + my->hex_mode = new_hex; + if ( !my->edit_autofocus ) + return TRUE; } + } + else if ( Param1 == SD_CHECKBOX_REGEXP ) + { + SendDlgMessage(hDlg, DM_SDSETVISIBILITY, my->hex_mode, 0); + } - SendDlgMessage(hDlg,DM_ENABLEREDRAW,TRUE,0); + if ( my->edit_autofocus && !my->recursive ) + { + if ( need_focus + || Param1 == SD_CHECKBOX_CASE + || Param1 == SD_CHECKBOX_WORDS + || Param1 == SD_CHECKBOX_REVERSE + || Param1 == SD_CHECKBOX_REGEXP + ){ + my->recursive = true; + SendDlgMessage(hDlg, DM_SETFOCUS, my->hex_mode ? SD_EDIT_HEX : SD_EDIT_TEXT, 0); + my->recursive = false; + } + } + + if (need_focus) return TRUE; - } + else + break; } + case DN_EDITCHANGE: + { + if ( Param1 == SD_EDIT_TEXT && SendDlgMessage(hDlg,DM_GETCHECK,SD_CHECKBOX_REGEXP,0) == BSTATE_CHECKED ) + SendDlgMessage(hDlg, DM_SDREXVISIBILITY, 1, 0); + break; + } 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); + MyDialogData *my = (MyDialogData *)SendDlgMessage(hDlg, DM_GETITEMDATA, SD_EDIT_TEXT, 0); + SendDlgMessage(hDlg, DM_SETFOCUS, (my->hex_mode ? SD_EDIT_HEX : SD_EDIT_TEXT), 0); return FALSE; } } @@ -2059,10 +2363,13 @@ static void PR_ViewerSearchMsg() { PreRedrawItem preRedrawItem=PreRedraw.Peek(); - ViewerSearchMsg((const wchar_t*)preRedrawItem.Param.Param1,(int)(INT_PTR)preRedrawItem.Param.Param2); + const wchar_t *name = (const wchar_t*)preRedrawItem.Param.Param1; + int percent = (int)(INT_PTR)preRedrawItem.Param.Param2; + int search_hex = (int)(INT_PTR)preRedrawItem.Param.Param3; + ViewerSearchMsg(name, percent, search_hex); } -void ViewerSearchMsg(const wchar_t *MsgStr,int Percent) +void ViewerSearchMsg(const wchar_t *MsgStr, int Percent, int SearchHex) { string strProgress; @@ -2093,6 +2400,7 @@ PreRedrawItem preRedrawItem=PreRedraw.Peek(); preRedrawItem.Param.Param1=(void*)MsgStr; preRedrawItem.Param.Param2=(LPVOID)(INT_PTR)Percent; + preRedrawItem.Param.Param3=(LPVOID)(INT_PTR)SearchHex; PreRedraw.SetParam(preRedrawItem.Param); } @@ -2109,15 +2417,17 @@ } } -static int hex2ss(const wchar_t *from, char *c1, int mb) +static int hex2ss(const wchar_t *from, char *c1, int mb, int *pos = 0) { - int nb, i, v, sub = 0; + int nb, i, v, sub = 0, ps = 0, p0 = (pos ? *pos : -1), p1 = -1; wchar_t ch; nb = i = v = 0; for (;;) { ch = *from++; + ++ps; + if (ch >= L'0' && ch <= L'9') sub = L'0'; else if (ch >= L'A' && ch <= L'F') sub = L'A' - 10; else if (ch >= L'a' && ch <= L'f') sub = L'a' - 10; @@ -2125,6 +2435,8 @@ { if (i > 0) { + if ( p0 >= 0 && ps > p0 && p1 < 0 ) + p1 = nb; c1[nb++] = (char)v; i = 0; } @@ -2136,6 +2448,8 @@ v = v*16 + ((int)ch - sub); if (++i >= 2) { + if ( p0 >= 0 && ps > p0 && p1 < 0 ) + p1 = nb; c1[nb++] = (char)v; i = 0; if (nb >= mb) @@ -2145,10 +2459,12 @@ #ifdef _DEBUG if (nb < mb) c1[nb] = '\0'; #endif + if ( p1 >= 0 && pos ) + *pos = p1; return nb; } -void Viewer::SearchTextTransform( UnicodeString &to, const wchar_t *from, bool hex2text ) +void Viewer::SearchTextTransform( UnicodeString &to, const wchar_t *from, bool hex2text, int &pos ) { int nb, i, v; char c1[128]; @@ -2156,7 +2472,7 @@ if (hex2text) { - nb = hex2ss(from, c1, ARRAYSIZE(c1)); + nb = hex2ss(from, c1, ARRAYSIZE(c1), &pos); if (IsUnicodeCodePage(VM.CodePage)) { @@ -2171,10 +2487,16 @@ ch = 0xffff; // encode L'\0' to += ch; } + if ( pos >= 0 ) + pos /= 2; } else { int nw = MultiByteToWideChar(VM.CodePage,0, c1,nb, ss,ARRAYSIZE(ss)); + if ( pos >= 0 ) + { + pos = MultiByteToWideChar(VM.CodePage,0, c1,pos, NULL,0); + } for (i=0; i < nw; ++i) if (!ss[i]) ss[i] = 0xffff; @@ -2184,8 +2506,12 @@ } else // text2hex { + int ps = 0, pd = 0, p0 = pos, p1 = -1; while (*from) { + if ( ps == p0 ) + p1 = pd; + ++ps; ch = *from++; if (0xffff == ch) // 0xffff - invalid unicode char ch = 0x0000; // it used to transfer '\0' in zero terminated string @@ -2199,398 +2525,737 @@ nb = 2; c1[0] = (char)HIBYTE(ch); c1[1] = (char)LOBYTE(ch); break; default: - nb = WideCharToMultiByte(VM.CodePage,0, &ch, 1, c1, 4, nullptr, nullptr); + nb = WideCharToMultiByte(VM.CodePage,0, &ch,1, c1,4, NULL,NULL); break; } ss2hex(to, c1, nb, L'\0'); + pd += nb * 3; } + pos = p1; } } -/* $ 27.01.2003 VVM - + �������� Next ����� �������� ������: - 0 - ���� ����� - 1 - ��������� ����� �� ������� ������ - 2 - ��������� ����� � ����� ����� -*/ +struct Viewer::search_data +{ + INT64 CurPos; + INT64 MatchPos; + const char *search_bytes; + const wchar_t *search_text; + int search_len; + int ch_size; + bool is_utf8; + bool first_Rex; + RegExp *pRex; -void Viewer::Search(int Next,int FirstChar) -{ - const wchar_t *TextHistoryName=L"SearchText"; - const wchar_t *HexMask=L"HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH "; - FarDialogItem SearchDlgData[]= + search_data() { - {DI_DOUBLEBOX,3,1,72,11,0,nullptr,nullptr,0,MSG(MViewSearchTitle)}, - {DI_TEXT,5,2,0,2,0,nullptr,nullptr,0,MSG(MViewSearchFor)}, - {DI_EDIT,5,3,70,3,0,TextHistoryName,nullptr,DIF_FOCUS|DIF_HISTORY|DIF_USELASTHISTORY,L""}, - {DI_FIXEDIT,5,3,70,3,0,nullptr,HexMask,DIF_MASKEDIT,L""}, - {DI_TEXT,3,4,0,4,0,nullptr,nullptr,DIF_SEPARATOR,L""}, - {DI_RADIOBUTTON,5,5,0,5,1,nullptr,nullptr,DIF_GROUP,MSG(MViewSearchForText)}, - {DI_RADIOBUTTON,5,6,0,6,0,nullptr,nullptr,0,MSG(MViewSearchForHex)}, - {DI_CHECKBOX,40,5,0,5,0,nullptr,nullptr,0,MSG(MViewSearchCase)}, - {DI_CHECKBOX,40,6,0,6,0,nullptr,nullptr,0,MSG(MViewSearchWholeWords)}, - {DI_CHECKBOX,40,7,0,7,0,nullptr,nullptr,0,MSG(MViewSearchReverse)}, - {DI_CHECKBOX,40,8,0,8,0,nullptr,nullptr,DIF_DISABLE,MSG(MViewSearchRegexp)}, - {DI_TEXT,3,9,0,9,0,nullptr,nullptr,DIF_SEPARATOR,L""}, - {DI_BUTTON,0,10,0,10,0,nullptr,nullptr,DIF_DEFAULTBUTTON|DIF_CENTERGROUP,MSG(MViewSearchSearch)}, - {DI_BUTTON,0,10,0,10,0,nullptr,nullptr,DIF_CENTERGROUP,MSG(MViewSearchCancel)}, - }; - MakeDialogItemsEx(SearchDlgData,SearchDlg); - string strSearchStr; - char search_bytes[128]; - string strMsgStr; - __int64 MatchPos=0; - int SearchLength,Case,WholeWords,ReverseSearch,Match,SearchRegexp; + CurPos = MatchPos = -1; + search_bytes = nullptr; + search_text = nullptr; + search_len = ch_size = 0; + is_utf8 = false; + first_Rex = true; + pRex = nullptr; + } - if (!ViewFile.Opened() || (Next && strLastSearchStr.IsEmpty())) - return; + ~search_data() + { + delete pRex; + } +}; - if (!strLastSearchStr.IsEmpty()) - strSearchStr = strLastSearchStr; +int Viewer::search_hex_forward( search_data* sd ) +{ + char *buff = (char *)Search_buffer; + const char *search_str = sd->search_bytes; + int bsize = Search_buffer_size * static_cast<int>(sizeof(wchar_t)), slen = sd->search_len; + INT64 to, cpos = sd->CurPos; + + bool up_half = cpos >= StartSearchPos; + if ( up_half ) + { + if ( (to = FileSize) - cpos <= bsize ) + SetFileSize(); + to = FileSize; + } else - strSearchStr.Clear(); + { + to = StartSearchPos + slen - 1; + if ( to > FileSize ) + to = FileSize; + } - SearchDlg[SD_RADIO_TEXT].Selected=!LastSearchHex; - SearchDlg[SD_RADIO_HEX].Selected=LastSearchHex; - SearchDlg[SD_CHECKBOX_CASE].Selected=LastSearchCase; - SearchDlg[SD_CHECKBOX_WORDS].Selected=LastSearchWholeWords; - SearchDlg[SD_CHECKBOX_REVERSE].Selected=LastSearchReverse; - SearchDlg[SD_CHECKBOX_REGEXP].Selected=LastSearchRegexp; + int nb = (to - cpos < bsize ? static_cast<int>(to - cpos) : bsize); + vseek(cpos, SEEK_SET); + DWORD nr = 0; + Reader.Read(buff, static_cast<DWORD>(nb), &nr); + int n1 = static_cast<int>(nr); + if ( n1 != nb ) + SetFileSize(); - if (SearchFlags.Check(REVERSE_SEARCH)) - SearchDlg[SD_CHECKBOX_REVERSE].Selected=!SearchDlg[SD_CHECKBOX_REVERSE].Selected; + if ( n1 < slen ) + { + if ( !up_half || StartSearchPos <= 0 ) + return -1; + sd->CurPos = 0; + return 0; + } - if (SearchDlg[SD_RADIO_HEX].Selected) + char *ps = buff; + while ( nullptr != (ps = static_cast<char *>(memchr(ps, search_str[0], n1-slen+1))) ) { - int nb = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); - strSearchStr.Clear(); - ss2hex(strSearchStr, search_bytes, nb, L'\0'); - SearchDlg[SD_EDIT_HEX].strData = strSearchStr; + if ( slen <= 1 || 0 == memcmp(ps+1, search_str+1, slen-1) ) + { + sd->MatchPos = cpos + static_cast<INT64>(ps - buff); + return +1; // found + } + ++ps; + n1 = static_cast<int>(nr - (ps - buff)); } + + sd->CurPos = cpos + nr - slen + 1; + return (up_half || sd->CurPos < StartSearchPos ? 0 : -1); +} + +int Viewer::search_hex_backward( search_data* sd ) +{ + char *buff = (char *)Search_buffer; + const char *search_str = sd->search_bytes; + int bsize = Search_buffer_size * static_cast<int>(sizeof(wchar_t)), slen = sd->search_len; + INT64 to, cpos = sd->CurPos; + + bool lo_half = cpos <= StartSearchPos; + if ( lo_half ) + { + to = 0; + } else - SearchDlg[SD_EDIT_TEXT].strData = strSearchStr; + { + to = StartSearchPos - slen + 1; + if ( to < 0 ) + to = 0; + } - SearchDlg[SD_EDIT_TEXT].UserData = this; + int nb = (cpos - to < bsize ? static_cast<int>(cpos - to) : bsize); + vseek(cpos-nb, SEEK_SET); + DWORD nr = 0; + Reader.Read(buff, static_cast<DWORD>(nb), &nr); + int n1 = static_cast<int>(nr); + if ( n1 != nb ) + { + SetFileSize(); + cpos = vtell(); + } - if (!Next) + if ( n1 < slen ) { - SearchFlags.Flags = 0; - Dialog Dlg(SearchDlg,ARRAYSIZE(SearchDlg),ViewerSearchDlgProc); - Dlg.SetPosition(-1,-1,76,13); - Dlg.SetHelp(L"ViewerSearch"); + if ( !lo_half ) + return -1; + SetFileSize(); + if ( StartSearchPos >= FileSize ) + return -1; + sd->CurPos = FileSize; + return 0; + } - if (FirstChar) + for ( char *ps = buff + n1 - 1; ps >= buff + slen - 1; --ps ) + { + if ( *ps == search_str[slen-1] ) { - Dlg.InitDialog(); - Dlg.Show(); - Dlg.ProcessKey(FirstChar); + if ( slen <= 1 || 0 == memcmp(ps-slen+1, search_str, slen-1) ) + { + sd->MatchPos = static_cast<INT64>(cpos-n1+(ps-slen+1-buff)); + return +1; + } } + } - Dlg.Process(); + sd->CurPos = cpos - nr + slen - 1; + return (lo_half || sd->CurPos > StartSearchPos ? 0 : -1); +} - if (Dlg.GetExitCode()!=SD_BUTTON_OK) - return; +int Viewer::search_text_forward( search_data* sd ) +{ + int bsize = 8192, slen = sd->search_len, ww = (LastSearchWholeWords ? 1 : 0); + wchar_t prev_char = L'\0', *buff = Search_buffer, *t_buff = (sd->is_utf8 ? buff + bsize : nullptr); + const wchar_t *search_str = sd->search_text; + INT64 to1, to, cpos = sd->CurPos; + + vseek(cpos, SEEK_SET); + if ( ww ) + prev_char = vgetc_prev(); + + bool up_half = cpos >= StartSearchPos; + if ( up_half ) + { + if ( (to = FileSize) - cpos <= bsize ) + SetFileSize(); + to = FileSize; } + else + { + to = StartSearchPos; + if ( to > FileSize ) + to = FileSize; + } - SearchHex=SearchDlg[SD_RADIO_HEX].Selected; - Case=SearchDlg[SD_CHECKBOX_CASE].Selected; - WholeWords=SearchDlg[SD_CHECKBOX_WORDS].Selected; - ReverseSearch=SearchDlg[SD_CHECKBOX_REVERSE].Selected; - SearchRegexp=SearchDlg[SD_CHECKBOX_REGEXP].Selected; + int nb = (to - cpos > bsize ? bsize : static_cast<int>(to - cpos)); + int nw = vread(buff, nb, t_buff); + to1 = vtell(); + if ( !up_half && nb + 3*(slen+ww) < bsize && !veof() ) + { + int nw1 = vread(buff+nw, 3*(slen+ww), t_buff ? t_buff+nw : nullptr); + nw1 = (nw1 > slen+ww-1 ? slen+ww-1 : nw1); + nw += nw1; + to1 = to + (t_buff ? GetStrBytesNum(t_buff, nw1) : sd->ch_size * nw1); + } - bool t_utf8 = !SearchHex && VM.CodePage == CP_UTF8; + int is_eof = (to1 >= FileSize ? 1 : 0), iLast = nw - slen - ww + is_eof; + if ( !LastSearchCase ) + CharUpperBuff(buff, nw); - if (SearchHex) + for ( int i = 0; i <= iLast; ++i ) { - strSearchStr = SearchDlg[SD_EDIT_HEX].strData; - SearchLength = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); - strSearchStr.Clear(); - ss2hex(strSearchStr, search_bytes, SearchLength, L' '); + if ( ww ) + { + if ( !is_word_div(i > 0 ? buff[i-1] : prev_char)) + continue; + if ( !(i == iLast && is_eof) && !is_word_div(buff[i+slen]) ) + continue; + } + if ( buff[i] != search_str[0] + || (slen > 1 && buff[i+1] != search_str[1]) + || (slen > 2 && 0 != wmemcmp(buff+i+2, search_str+2, slen-2)) + ) continue; + + sd->MatchPos = cpos + GetStrBytesNum(t_buff, i); + sd->search_len = GetStrBytesNum(t_buff+i, slen); + return +1; } + + if ( up_half && is_eof ) + { + sd->CurPos = 0; + return (StartSearchPos > 0 ? 0 : -1); + } else { - strSearchStr = SearchDlg[SD_EDIT_TEXT].strData; - SearchLength = (int)strSearchStr.GetLength(); - size_t pos = 0; - while (strSearchStr.Pos(pos, 0xffff)) - strSearchStr.Replace(pos, 1, L'\0'); + if ( iLast < 0 || (!up_half && to1 > StartSearchPos) ) + return -1; + sd->CurPos = to1; + return 0; } +} - strLastSearchStr = strSearchStr; - LastSearchHex=SearchHex; - LastSearchCase=Case; - LastSearchWholeWords=WholeWords; +int Viewer::search_text_backward( search_data* sd ) +{ + int bsize = 8192, slen = sd->search_len, ww = (LastSearchWholeWords ? 1 : 0); + wchar_t *buff = Search_buffer, *t_buff = (sd->is_utf8 ? buff + bsize : nullptr); + const wchar_t *search_str = sd->search_text; + INT64 to1, to, cpos = sd->CurPos; - if (!SearchFlags.Check(REVERSE_SEARCH)) - LastSearchReverse=ReverseSearch; + bool up_half = cpos > StartSearchPos; + to = (up_half ? StartSearchPos : 0); - LastSearchRegexp=SearchRegexp; + int nb = (cpos - to > bsize ? bsize : static_cast<int>(cpos- to)); + if ( up_half && nb + 3*(slen+ww) < bsize && cpos > nb ) + { + if ( sd->ch_size > 0 ) + { + nb += sd->ch_size * (slen + ww - 1); + if (cpos < nb) + nb = static_cast<int>(cpos); + } + else + { + to1 = cpos - nb - 3*(slen + ww - 1); + if (to1 < 0) + to1 = 0; + int nb1 = static_cast<int>(cpos - nb - to1); + vseek(to1, SEEK_SET); + int nw1 = vread(buff, nb1, t_buff); + if ( nw1 > slen + ww - 1 ) + nb1 = GetStrBytesNum(t_buff + nw1 - (slen + ww - 1), slen + ww - 1); + nb += nb1; + } + } - if (!SearchLength) - return; + cpos -= nb; + vseek(cpos, SEEK_SET); + int nw = vread(buff, nb, t_buff); + if ( !LastSearchCase ) + CharUpperBuff(buff, nw); + int is_eof = (veof() ? 1 : 0), iFirst = ww * (cpos > 0 ? 1 : 0), iLast = nw - slen - ww + ww*is_eof; + for ( int i = iLast; i >= iFirst; --i ) { - TPreRedrawFuncGuard preRedrawFuncGuard(PR_ViewerSearchMsg); - //SaveScreen SaveScr; - SetCursorType(FALSE,0); - strMsgStr = strSearchStr; + if ( ww ) + { + if ( i > 0 && !is_word_div(buff[i-1]) ) + continue; + if ( !(i == iLast && is_eof) && !is_word_div(buff[i+slen]) ) + continue; + } + if ( buff[i] != search_str[0] + || (slen > 1 && buff[i+1] != search_str[1]) + || (slen > 2 && 0 != wmemcmp(buff+i+2, search_str+2, slen-2)) + ) continue; - if (strMsgStr.GetLength()+18 > static_cast<DWORD>(ObjWidth)) - TruncStrFromEnd(strMsgStr, ObjWidth-18); + sd->MatchPos = cpos + GetStrBytesNum(t_buff, i); + sd->search_len = GetStrBytesNum(t_buff+i, slen); + return +1; + } - if (!SearchHex) - InsertQuote(strMsgStr); + int ret = 0; + if ( up_half ) + ret = (cpos <= StartSearchPos ? -1 : 0); + else + { + if ( cpos <= 0 ) + { + SetFileSize(); + cpos = FileSize; + ret = (StartSearchPos >= FileSize ? -1 : 0); + } + } + sd->CurPos = cpos; + return ret; +} - if (SearchHex) - Case = 1 + (WholeWords = 0); +int Viewer::read_line(wchar_t *buf, wchar_t *tbuf, INT64 cpos, int adjust, INT64 &lpos, int &lsize) +{ + int llen = 0; - if (!Case && !SearchHex) - strSearchStr.Upper(); + INT64 save_FilePos = FilePos, save_LastPage = LastPage; + int save_Hex = VM.Hex, save_Wrap = VM.Wrap, save_WordWrap = VM.WordWrap; + VM.Hex = VM.Wrap = VM.WordWrap = 0; - SelectSize = 0; + FilePos = cpos; + if ( adjust ) + { + if ( adjust > 0 ) + AdjustFilePos(); + else + Up(1); + } - if (Next) + vseek(lpos = vString.nFilePos = FilePos, SEEK_SET); + vString.linesize = 0; + ReadString(&vString, -1, false); // read unwrapped text line + + vseek(FilePos, SEEK_SET); + llen = vread(buf, lsize = vString.linesize, tbuf); + if ( llen > 0 && vString.have_eol ) // remove eol-s + { + --llen; + if ( llen > 0 && (buf[llen-1] == L'\r' || buf[llen-1] == L'\n') ) + --llen; + } + buf[llen >= 0 ? llen : 0] = L'\0'; + + VM.Hex = save_Hex; VM.Wrap = save_Wrap; VM.WordWrap = save_WordWrap; + FilePos = save_FilePos; LastPage = save_LastPage; + return llen; +} + +int Viewer::search_regex_forward( search_data* sd ) +{ + assert(sd->pRex); + assert(Search_buffer_size >= 2*MAX_VIEWLINEB); + + wchar_t *line = Search_buffer, *t_line = sd->is_utf8 ? Search_buffer + MAX_VIEWLINEB : nullptr; + INT64 cpos = sd->CurPos, bpos = 0; + + int first = (sd->first_Rex ? +1 : 0); + sd->first_Rex = false; + bool up_half = cpos >= StartSearchPos; + + int lsize = 0, nw = read_line(line, t_line, cpos, first, bpos, lsize); + if ( lsize <= 0 ) + { + sd->CurPos = 0; + return (up_half && StartSearchPos > 0 ? 0 : -1); + } + + int off = 0; + for (;;) + { + if ( off > nw ) + break; + + SMatch m[1]; + int n = static_cast<int>(ARRAYSIZE(m)); + if ( !sd->pRex->SearchEx(line, line+off, line+nw, m, n) ) // doesn't match + break; + + INT64 fpos = bpos + GetStrBytesNum(t_line, m[0].start); + if ( fpos < cpos ) { - if (Next == 2) - { - SearchFlags.Set(SEARCH_MODE2); - LastSelPos = ReverseSearch?FileSize:0; - } - else - { - LastSelPos = SelectPos + (ReverseSearch?-1:1); - } + off = m[0].start + 1; // skip + continue; } - else + else if ( !up_half && fpos >= StartSearchPos ) { - LastSelPos = FilePos; + break; // done - not found + } + else // found + { + sd->MatchPos = fpos; + sd->search_len = GetStrBytesNum(t_line+off, m[0].end - m[0].start); + return +1; + } + } - if (!LastSelPos || LastSelPos == FileSize) - SearchFlags.Set(SEARCH_MODE2); + sd->CurPos = vtell(); + if ( up_half ) + { + if ( veof() ) + { + sd->CurPos = 0; + return (StartSearchPos > 0 ? 0 : -1); } + return 0; + } + else + { + return (sd->CurPos >= StartSearchPos ? -1 : 0); + } +} - vseek(LastSelPos,SEEK_SET); - Match = 0; +int Viewer::search_regex_backward( search_data* sd ) +{ + assert(sd->pRex); + assert(Search_buffer_size >= 2*MAX_VIEWLINEB); - if (SearchLength > 0 && (!ReverseSearch || LastSelPos > 0)) + wchar_t *line = Search_buffer, *t_line = sd->is_utf8 ? Search_buffer + MAX_VIEWLINEB : nullptr; + INT64 cpos = sd->CurPos, bpos = 0, prev_pos = -1; + + bool up_half = cpos > StartSearchPos; + + int off=0, lsize=0, nw, prev_len = -1, flen; + nw = read_line(line, t_line, cpos, -1, bpos, lsize); + for (;;) + { + if ( lsize <= 0 || off > nw ) + break; + + SMatch m[1]; + int n = static_cast<int>(ARRAYSIZE(m)); + if ( !sd->pRex->SearchEx(line, line+off, line+nw, m, n) ) + break; + + INT64 fpos = bpos + GetStrBytesNum(t_line, m[0].start); + flen = GetStrBytesNum(t_line + m[0].start, m[0].end - m[0].start); + if ( fpos+flen > cpos ) + break; + + if ( !(up_half && fpos+flen <= StartSearchPos) ) { - wchar_t *Buf = new wchar_t[8192 + 8192], *t_Buf = t_utf8 ? Buf + 8192 : nullptr; - int buf_size = 8192, seek_size = 1; - char *byte_buff = nullptr; - if (SearchHex) - { - byte_buff = (char *)Buf; - buf_size *= 2*(int)sizeof(wchar_t); - seek_size = IsUnicodeCodePage(VM.CodePage) ? 2 : 1; - } + prev_pos = fpos; + prev_len = flen; + } - __int64 CurPos=LastSelPos; - int BufSize = buf_size; + off = m[0].start + 1; // skip + continue; + } - if (ReverseSearch) - { - /* $ 01.08.2000 KM - ������� �������� CurPos � ���� Whole words - */ - if (WholeWords) - CurPos -= BufSize/seek_size - SearchLength/seek_size + 1; - else - CurPos -= BufSize/seek_size - SearchLength/seek_size; + if ( prev_len >= 0 ) + { + sd->MatchPos = prev_pos; + sd->search_len = prev_len; + return +1; + } + + if ( (sd->CurPos = bpos) <= 0 ) + { + SetFileSize(); + sd->CurPos = FileSize; + return (StartSearchPos >= FileSize ? -1 : 0); + } + return (up_half && bpos <= StartSearchPos ? -1 : 0); +} - if (CurPos<0) - BufSize += (int)CurPos * seek_size; - } - int ReadSize; - TaskBar TB; - wakeful W; - INT64 StartPos = vtell(); - DWORD StartTime = GetTickCount(); +/* + + �������� Next ����� �������� ������: + 0 - ���� ����� + 1 - ��������� ����� �� ������� ������ +-1 - ��������� ����� �� ������� ������ � ��������������� ����������� + 2 - ��������� ����� � �����/���� ����� +*/ +void Viewer::Search(int Next,int FirstChar) +{ + if (!ViewFile.Opened() || (Next && strLastSearchStr.IsEmpty())) + return; - while (!Match) - { - /* $ 01.08.2000 KM - �������� ������ if (ReverseSearch && CurPos<0) �� if (CurPos<0), - ��� ��� ��� ����� ����� � LastSelPos=0xFFFFFFFF, ����� - ���������� ��� � �� ������. - */ - if (CurPos < 0) - CurPos = 0; + string strSearchStr, strMsgStr; + char search_bytes[128]; + int Case,WholeWords,ReverseSearch,SearchRegexp,SearchHex; - vseek(CurPos, SEEK_SET); + SearchHex = LastSearchHex; + Case = LastSearchCase; + WholeWords = LastSearchWholeWords; + ReverseSearch = LastSearchReverse; + SearchRegexp = LastSearchRegexp; + strSearchStr.Clear(); + if (!strLastSearchStr.IsEmpty()) + strSearchStr = strLastSearchStr; - if (SearchHex) - { - DWORD nr = 0; - Reader.Read(byte_buff, (DWORD)BufSize, &nr); - ReadSize = (int)nr; - } - else - { - ReadSize = vread(Buf, BufSize, t_Buf); - } - if (ReadSize <= 0) - break; + search_data sd; + int (Viewer::* searcher)( Viewer::search_data *p_sd ) = nullptr; - DWORD CurTime=GetTickCount(); + if ( !Next ) + { + const wchar_t *TextHistoryName=L"SearchText"; + const wchar_t *HexMask = L"HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH " ; + FarDialogItem SearchDlgData[]= + { + {DI_DOUBLEBOX,3,1,72,11,0,nullptr,nullptr,0,MSG(MViewSearchTitle)}, + {DI_TEXT,5,2,0,2,0,nullptr,nullptr,0,MSG(MViewSearchFor)}, + {DI_EDIT,5,3,70,3,0,TextHistoryName,nullptr,DIF_FOCUS|DIF_HISTORY|DIF_USELASTHISTORY,L""}, + {DI_FIXEDIT,5,3,70,3,0,nullptr,HexMask,DIF_MASKEDIT,L""}, + {DI_TEXT,3,4,0,4,0,nullptr,nullptr,DIF_SEPARATOR,L""}, + {DI_RADIOBUTTON,5,5,0,5,1,nullptr,nullptr,DIF_GROUP,MSG(MViewSearchForText)}, + {DI_RADIOBUTTON,5,6,0,6,0,nullptr,nullptr,0,MSG(MViewSearchForHex)}, + {DI_CHECKBOX,40,5,0,5,0,nullptr,nullptr,0,MSG(MViewSearchCase)}, + {DI_CHECKBOX,40,6,0,6,0,nullptr,nullptr,0,MSG(MViewSearchWholeWords)}, + {DI_CHECKBOX,40,7,0,7,0,nullptr,nullptr,0,MSG(MViewSearchReverse)}, + {DI_CHECKBOX,40,8,0,8,0,nullptr,nullptr,DIF_DISABLE,MSG(MViewSearchRegexp)}, + {DI_TEXT,3,9,0,9,0,nullptr,nullptr,DIF_SEPARATOR,L""}, + {DI_BUTTON,0,10,0,10,0,nullptr,nullptr,DIF_DEFAULTBUTTON|DIF_CENTERGROUP,MSG(MViewSearchSearch)}, + {DI_BUTTON,0,10,0,10,0,nullptr,nullptr,DIF_CENTERGROUP,MSG(MViewSearchCancel)}, + }; + MakeDialogItemsEx(SearchDlgData,SearchDlg); - if (CurTime-StartTime>RedrawTimeout) - { - StartTime=CurTime; + SearchDlg[SD_RADIO_TEXT].Selected=!LastSearchHex; + SearchDlg[SD_RADIO_HEX].Selected=LastSearchHex; + SearchDlg[SD_CHECKBOX_CASE].Selected=LastSearchCase; + SearchDlg[SD_CHECKBOX_WORDS].Selected=LastSearchWholeWords; + SearchDlg[SD_CHECKBOX_REVERSE].Selected=LastSearchReverse; + SearchDlg[SD_CHECKBOX_REGEXP].Selected=LastSearchRegexp; - if (CheckForEscSilent()) - { - if (ConfirmAbortOp()) - { - Redraw(); - return; - } - } + if (SearchDlg[SD_RADIO_HEX].Selected) + { + int nb = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); + strSearchStr.Clear(); + ss2hex(strSearchStr, search_bytes, nb, L'\0'); + SearchDlg[SD_EDIT_HEX].strData = strSearchStr; + } + else + SearchDlg[SD_EDIT_TEXT].strData = strSearchStr; - INT64 Total=ReverseSearch?StartPos:FileSize-StartPos; - INT64 Current=_abs64(CurPos-StartPos); - int Percent=Total>0?static_cast<int>(Current*100/Total):-1; - // � ����� ���� ���� ����������� �������, �� ��������� - // �������� ����� �� ���� 100. ����������� ��� ������. - if (Percent>100) - { - SetFileSize(); - Total=FileSize-StartPos; - Percent=Total>0?static_cast<int>(Current*100/Total):-1; - if (Percent>100) - { - Percent=100; - } - } - ViewerSearchMsg(strMsgStr,Percent); - } + MyDialogData my; + // + my.viewer = this; + my.edit_autofocus = (ViOpt.SearchEditFocus != 0); + my.hex_mode = (LastSearchHex != 0); + my.recursive = false; + // + SearchDlg[SD_EDIT_TEXT].UserData = &my; - /* $ 01.08.2000 KM - ������� ����� �������� �� Case sensitive � Hex - � ���� ���, ����� Buf ��������� � ������� �������� - */ - if (!Case && !SearchHex) - CharUpperBuff(Buf, ReadSize); + Dialog Dlg(SearchDlg,ARRAYSIZE(SearchDlg),ViewerSearchDlgProc); + Dlg.SetPosition(-1,-1,76,13); + Dlg.SetHelp(L"ViewerSearch"); - /* $ 01.08.2000 KM - ����� ����� ������ ����� ��������� ��������� ������ - � Buf � ������� ��������, ���� ����� �� ���������������� - ��� �� ���� Hex-������ � � ���� � ���� ����������� ��� ������ - */ - int MaxSize=ReadSize-SearchLength+1; - int Increment=ReverseSearch ? -seek_size : +seek_size; + if (FirstChar) + { + Dlg.InitDialog(); + Dlg.Show(); + Dlg.ProcessKey(FirstChar); + } - for (int I=ReverseSearch ? MaxSize-1:0; I<MaxSize && I>=0; I+=Increment) - { - /* $ 01.08.2000 KM - ��������� ������ "Whole words" - */ - int locResultLeft=FALSE; - int locResultRight=FALSE; + Dlg.Process(); - if (WholeWords) - { - if (I) - { - if (IsSpace(Buf[I-1]) || IsEol(Buf[I-1]) || - (wcschr(Opt.strWordDiv,Buf[I-1]))) - locResultLeft=TRUE; - } - else - { - locResultLeft=TRUE; - } + if (Dlg.GetExitCode()!=SD_BUTTON_OK) + return; - if (ReadSize!=BufSize && I+SearchLength>=ReadSize) - locResultRight=TRUE; - else if (I+SearchLength<ReadSize && - (IsSpace(Buf[I+SearchLength]) || IsEol(Buf[I+SearchLength]) || - (wcschr(Opt.strWordDiv,Buf[I+SearchLength])))) - locResultRight=TRUE; - } - else - { - locResultLeft=TRUE; - locResultRight=TRUE; - } + SearchHex=SearchDlg[SD_RADIO_HEX].Selected; + Case=SearchDlg[SD_CHECKBOX_CASE].Selected; + WholeWords=SearchDlg[SD_CHECKBOX_WORDS].Selected; + ReverseSearch=SearchDlg[SD_CHECKBOX_REVERSE].Selected; + SearchRegexp=SearchDlg[SD_CHECKBOX_REGEXP].Selected; - if (!SearchHex) - { - Match = locResultLeft && locResultRight && strSearchStr.At(0) == Buf[I] && - ( SearchLength==1 || - ( strSearchStr.At(1) == Buf[I+1] && - (SearchLength==2 || !memcmp(strSearchStr.CPtr()+2,&Buf[I+2],(SearchLength-2)*sizeof(wchar_t))) - ) - ) - ; - } - else - { - if ((Match = search_bytes[0] == byte_buff[I+0]) && SearchLength > 1) - if ((Match = search_bytes[1] == byte_buff[I+1]) && SearchLength > 2) - if ((Match = search_bytes[2] == byte_buff[I+2]) && SearchLength > 3) - if ((Match = search_bytes[3] == byte_buff[I+3]) && SearchLength > 4) - Match = !memcmp(search_bytes+4, byte_buff+I+4, SearchLength-4); - } + if (SearchHex) + { + strSearchStr = SearchDlg[SD_EDIT_HEX].strData; + int len = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); + strSearchStr.Clear(); + ss2hex(strSearchStr, search_bytes, len, L' '); + } + else + { + strSearchStr = SearchDlg[SD_EDIT_TEXT].strData; + size_t pos = 0; + while (strSearchStr.Pos(pos, 0xffff)) + strSearchStr.Replace(pos, 1, L'\0'); + } + } - if (Match) + LastSearchCase = Case; + LastSearchWholeWords = WholeWords; + LastSearchReverse = ReverseSearch; + LastSearchRegexp = SearchRegexp; + + if (Next == -1) + ReverseSearch = !ReverseSearch; + + strMsgStr = strLastSearchStr = strSearchStr; + if (strMsgStr.GetLength()+18 > static_cast<DWORD>(ObjWidth)) + TruncStrFromEnd(strMsgStr, ObjWidth-18); + + sd.search_len = (int)strSearchStr.GetLength(); + if (0 != (LastSearchHex = SearchHex)) + { + sd.search_len = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); + sd.search_bytes = search_bytes; + sd.ch_size = 1; + Case = 1 + (WholeWords = SearchRegexp = 0); + searcher = (ReverseSearch ? &Viewer::search_hex_backward : &Viewer::search_hex_forward); + } + else + { + sd.is_utf8 = VM.CodePage == CP_UTF8; + sd.ch_size = getCharSize(VM.CodePage); + sd.search_text = strSearchStr.CPtr(); + + if ( SearchRegexp ) + { + WholeWords = 0; + searcher = (ReverseSearch ? &Viewer::search_regex_backward : &Viewer::search_regex_forward); + InsertRegexpQuote(strMsgStr); + sd.pRex = new RegExp; + string strSlash = strSearchStr; + InsertRegexpQuote(strSlash); + if ( !sd.pRex->Compile(strSlash, OP_PERLSTYLE | OP_OPTIMIZE | (Case ? 0 : OP_IGNORECASE)) ) + return; // wrong regular expression... + } + else + { + searcher = (ReverseSearch ? &Viewer::search_text_backward : &Viewer::search_text_forward); + InsertQuote(strMsgStr); + } + } + + if (!Case && !SearchRegexp) + { + strSearchStr.Upper(); + sd.search_text = strSearchStr.CPtr(); + } + + int found = 0; + + int search_direction = ReverseSearch ? -1 : +1; + switch (Next) + { + case 2: + StartSearchPos = LastSelectPos = (ReverseSearch ? FileSize : 0); + break; + case +1: case -1: + if ( SelectPos >= 0 && LastSelectSize >= 0 ) + { + if (sd.ch_size >= 1) + LastSelectPos = SelectPos + (ReverseSearch ? LastSelectSize-sd.ch_size : sd.ch_size); + else + { + INT64 prev_pos = SelectPos; + vseek(SelectPos, SEEK_SET); + for (;;) { - MatchPos = CurPos + I / seek_size; - if (t_utf8) + wchar_t ch; + bool ok_getc = vgetc(&ch); + LastSelectPos = vtell(); + if (!ReverseSearch || !ok_getc) + break; + if ( LastSelectPos >= SelectPos + LastSelectSize ) { - MatchPos = CurPos + GetStrBytesNum(t_Buf, I); - SearchLength = GetStrBytesNum(t_Buf+I, SearchLength); + LastSelectPos = prev_pos; + break; } - break; + prev_pos = LastSelectPos; } } + if (search_direction != LastSearchDirection) + StartSearchPos = LastSelectPos; + else if ( LastSelectPos == StartSearchPos ) // ������ � + found = -1; // ������������ - if ((ReverseSearch && CurPos <= 0) || (!ReverseSearch && veof())) - break; + break; + } // else pass to case 0 (below) + case 0: + LastSelectSize = SelectSize = -1; + StartSearchPos = LastSelectPos = (ReverseSearch ? EndOfScreen(0) : BegOfScreen()); + break; + } + LastSearchDirection = search_direction; - int asz = buf_size; - if (t_utf8) - asz = GetStrBytesNum(t_Buf, ReadSize); + if (!sd.search_len || (__int64)sd.search_len > FileSize) + return; - if (ReverseSearch) + sd.CurPos = LastSelectPos; + if ( !found ) + { + TPreRedrawFuncGuard preRedrawFuncGuard(PR_ViewerSearchMsg); + SetCursorType(FALSE,0); + + DWORD start_time = GetTickCount(); + for (;;) + { + found = (this->*searcher)(&sd); + if ( found != 0 ) + break; + + DWORD cur_time = GetTickCount(); + if ( cur_time - start_time > RedrawTimeout ) + { + start_time = cur_time; + + if (CheckForEscSilent()) { - /* $ 01.08.2000 KM - ������� �������� CurPos � ���� Whole words - */ - if (WholeWords) - CurPos -= asz/seek_size - SearchLength/seek_size + 1; - else - CurPos -= asz/seek_size - SearchLength/seek_size; + if (ConfirmAbortOp()) + { + Redraw(); + return; + } } - else + + int percent = -1; + INT64 done, total = FileSize; + if ( total > 0 ) { - if (WholeWords) - CurPos += asz/seek_size - SearchLength/seek_size + 1; + if ( !ReverseSearch ) + { + if ( sd.CurPos >= StartSearchPos ) + done = sd.CurPos - StartSearchPos; + else + done = (FileSize - StartSearchPos) + sd.CurPos; + } else - CurPos += asz/seek_size - SearchLength/seek_size; + { + if ( sd.CurPos <= StartSearchPos ) + done = StartSearchPos - sd.CurPos; + else + done = StartSearchPos + (FileSize - sd.CurPos); + } + percent = static_cast<int>(done*100/total); } + ViewerSearchMsg(strMsgStr, percent, SearchHex); } - - delete[] Buf; } } - if (Match) + if ( sd.MatchPos >= 0 ) { - /* $ 24.01.2003 KM - ! �� �������� ������ �������� �� ���� ������ �� - ���� ������������ ����. - */ - SelectText(MatchPos,SearchLength,ReverseSearch?0x2:0); - // ������� ��������� �� ��������� ����� ������ �� ����. + SelectText(sd.MatchPos, sd.search_len, ReverseSearch?0x2:0); + LastSelectSize = SelectSize; + + // ������� ��������� �� ��������� �������� ������ �� ����. int FromTop=(ScrY-(Opt.ViOpt.ShowKeyBar?2:1))/4; if (FromTop<0 || FromTop>ScrY) FromTop=0; - for (int i=0; i<FromTop; i++) - Up(); + Up(FromTop); AdjustSelPosition = TRUE; Show(); @@ -2598,24 +3263,13 @@ } else { - //Show(); - /* $ 27.01.2003 VVM - + ����� ������� ������ ������� � ������� ������ � �����/���� */ - if (SearchFlags.Check(SEARCH_MODE2)) - { - Message(MSG_WARNING,1,MSG(MViewSearchTitle), - (SearchHex?MSG(MViewSearchCannotFindHex):MSG(MViewSearchCannotFind)),strMsgStr,MSG(MOk)); - } - else - { - if (!Message(MSG_WARNING,2,MSG(MViewSearchTitle), - (SearchHex?MSG(MViewSearchCannotFindHex):MSG(MViewSearchCannotFind)),strMsgStr, - (ReverseSearch?MSG(MViewSearchFromEnd):MSG(MViewSearchFromBegin)), - MSG(MHYes),MSG(MHNo))) - { - Search(2,0); - } - } + Message( + MSG_WARNING, 1, + MSG(MViewSearchTitle), + (SearchHex ? MSG(MViewSearchCannotFindHex) : MSG(MViewSearchCannotFind)), + strMsgStr, + MSG(MOk) + ); } } @@ -2625,37 +3279,31 @@ 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; @@ -2663,7 +3311,6 @@ ConsoleTitle::SetFarTitle(strTitle); } - void Viewer::SetTempViewName(const wchar_t *Name, BOOL DeleteFolder) { if (Name && *Name) @@ -2677,7 +3324,6 @@ Viewer::DeleteFolder=DeleteFolder; } - void Viewer::SetTitle(const wchar_t *Title) { if (!Title) @@ -2686,19 +3332,16 @@ 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) @@ -2825,10 +3468,15 @@ if (IsUnicodeCodePage(VM.CodePage)) { - Reader.Read(Buf, Count*2, &ReadSize); + int rev = (CP_REVERSEBOM == VM.CodePage ? 1 : 0); + + Reader.Read(Buf, Count, &ReadSize); if (0 != (ReadSize & 1)) - ((char *)Buf)[ReadSize++] = '\0'; - + { + ((char *)Buf)[ReadSize-1+rev] = (char)(REPLACE_CHAR & 0xff); + ((char *)Buf)[ReadSize-0-rev] = (char)(REPLACE_CHAR >> 8); + ++ReadSize; + } if (CP_REVERSEBOM == VM.CodePage) { for (DWORD i=0; i<ReadSize; i+=2) @@ -2838,7 +3486,6 @@ ((char *)Buf)[i+1] = t; } } - ReadSize /= 2; } else @@ -2871,15 +3518,11 @@ bool Viewer::vseek(__int64 Offset, int Whence) { - int seek_size = IsUnicodeCodePage(VM.CodePage) ? 2 : 1; - Offset *= seek_size; - if (FILE_CURRENT == Whence) { if (vgetc_ready) { int tail = vgetc_cb - vgetc_ib; - tail += (seek_size - 1) * (tail & 1); Offset += tail; vgetc_ready = false; } @@ -2898,9 +3541,6 @@ if (vgetc_ready) Ptr -= (vgetc_cb - vgetc_ib); - if (IsUnicodeCodePage(VM.CodePage)) - Ptr=(Ptr+(Ptr&1))/2; - return Ptr; } @@ -2927,9 +3567,6 @@ DWORD nr = 0; Reader.Read(vgetc_buffer + vgetc_cb, (DWORD)(ARRAYSIZE(vgetc_buffer)-vgetc_cb), &nr); vgetc_cb += (int)nr; - - if (0 != (vgetc_cb & 1) && IsUnicodeCodePage(VM.CodePage)) - vgetc_buffer[vgetc_cb++] = 0; } vgetc_ready = true; @@ -2951,11 +3588,17 @@ switch (VM.CodePage) { case CP_REVERSEBOM: - *pCh = (wchar_t)((vgetc_buffer[vgetc_ib] << 8) | vgetc_buffer[vgetc_ib+1]); + if (vgetc_ib == vgetc_cb-1) + *pCh = REPLACE_CHAR; + else + *pCh = (wchar_t)((vgetc_buffer[vgetc_ib] << 8) | vgetc_buffer[vgetc_ib+1]); vgetc_ib += 2; break; case CP_UNICODE: - *pCh = (wchar_t)((vgetc_buffer[vgetc_ib+1] << 8) | vgetc_buffer[vgetc_ib]); + if (vgetc_ib == vgetc_cb-1) + *pCh = REPLACE_CHAR; + else + *pCh = (wchar_t)((vgetc_buffer[vgetc_ib+1] << 8) | vgetc_buffer[vgetc_ib]); vgetc_ib += 2; break; case CP_UTF8: @@ -2978,6 +3621,54 @@ return true; } +wchar_t Viewer::vgetc_prev() +{ + INT64 pos = vtell(); + if ( pos <= 0 ) + return L'\0'; + + int ch_size = getCharSize(VM.CodePage); + if ( pos < ch_size ) + return REPLACE_CHAR; + + int nb = (ch_size >= 1 ? ch_size : (pos > 4 ? 4 : static_cast<int>(pos))); + DWORD nr = 0; + + char ss[4]; + if ( vseek(-nb, SEEK_CUR) ) + Reader.Read(ss, static_cast<DWORD>(nb), &nr); + + vseek(pos, SEEK_SET); + + wchar_t ch = REPLACE_CHAR; + if ( static_cast<int>(nr) == nb ) + { + switch ( VM.CodePage ) + { + case CP_REVERSEBOM: + ch = MAKEWORD(ss[1], ss[0]); + break; + case CP_UNICODE: + ch = MAKEWORD(ss[0], ss[1]); + break; + case CP_UTF8: + { + int tail = 0; + wchar_t w[4]; + int nw = utf8_to_WideChar(ss, nb, w,nullptr, 4,tail); + if ( !tail && nw > 0 ) + ch = w[nw-1]; + break; + } + default: + MultiByteToWideChar(VM.CodePage, 0, (LPCSTR)ss,1, &ch,1); + break; + } + } + return ch; +} + + #define RB_PRC 3 #define RB_HEX 4 #define RB_DEC 5 @@ -3060,9 +3751,6 @@ // Percent=0; Offset=FileSize/100*Percent; - if (IsUnicodeCodePage(VM.CodePage)) - Offset*=2; - while (ToPercent64(Offset,FileSize)<Percent) Offset++; } @@ -3094,31 +3782,16 @@ // Percent=0; Offset=FileSize/100*Percent; - if (IsUnicodeCodePage(VM.CodePage)) - Offset*=2; - while (ToPercent64(Offset,FileSize)<Percent) Offset++; } } - if (Relative) - { - if (Relative==-1 && Offset>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; // ��� ��� ����� ����� ���� + FilePos = (Relative ? FilePos + Offset*Relative : Offset); + FilePos = (FilePos < 0 ? 0 : (FilePos > FileSize ? FileSize : FilePos)); } - // ������� AdjustFilePos(); -// LastSelPos=FilePos; if (!(Flags&VSP_NOREDRAW)) Show(); } @@ -3129,6 +3802,9 @@ if (!VM.Hex) { + int ch_size = getCharSize(VM.CodePage); + FilePos -= FilePos % ch_size; + vseek(FilePos, SEEK_SET); if (VM.CodePage != CP_UTF8) { @@ -3140,7 +3816,7 @@ if (vgetc_ib < vgetc_cb) { if (0x80 == (vgetc_buffer[vgetc_ib] & 0xC0)) - { + { if (++vgetc_ib < vgetc_cb) { if (0x80 == (vgetc_buffer[vgetc_ib] & 0xC0)) @@ -3152,18 +3828,18 @@ } } } - } + } else - { + { vgetc(&ch); } } } - FilePos = vtell(); - Up(); - } + FilePos = vtell(); + Up(1); } +} void Viewer::SetFileSize() { @@ -3173,13 +3849,6 @@ UINT64 uFileSize=0; // BUGBUG, sign ViewFile.GetSize(uFileSize); FileSize=uFileSize; - - /* $ 20.02.2003 IS - ����� ���������� FilePos � FileSize, FilePos �� ������� ������ - �������� � ��� ����, ������ FileSize ���� ���� ������ - */ - if (IsUnicodeCodePage(VM.CodePage)) - FileSize=(FileSize+(FileSize&1))/2; } @@ -3190,85 +3859,50 @@ Flags=SelectFlags; } -/* $ 19.01.2001 SVS - �������� - � ������� ������������� ������. - Flags=0x01 - �������� (����� Show()) - 0x02 - "������� �����" ? -*/ -void Viewer::SelectText(const __int64 &MatchPos,const __int64 &SearchLength, const DWORD Flags) +// Flags=0x01 - �������� [����� Show()] +// 0x02 - "������� �����" ? +// +void Viewer::SelectText(const __int64 &match_pos,const __int64 &search_len, const DWORD flags) { if (!ViewFile.Opened()) return; - int buff_size = 1024; - wchar_t *Buf = Up_buffer, *tBuf = (!VM.Hex && VM.CodePage == CP_UTF8) ? Buf + buff_size : nullptr; - __int64 StartLinePos = -1, SearchLinePos = MatchPos - buff_size; - if (SearchLinePos < 0) - { - buff_size += (int)SearchLinePos; - SearchLinePos = 0; - } + SelectPos = match_pos; + SelectSize = search_len; + SelectFlags = flags; + if ( SelectSize < 0 ) + return; - vseek(SearchLinePos, SEEK_SET); - int ReadSize = vread(Buf, buff_size, tBuf); - - for (int I=ReadSize-1; I >= 0; I--) - if (Buf[I]==L'\n' || Buf[I]==L'\r') + if ( VM.Hex ) { - if (tBuf) - StartLinePos = MatchPos - GetStrBytesNum(tBuf+I, ReadSize-I); - else - StartLinePos = SearchLinePos+I; - break; + FilePos = (FilePos & 0xf) | (SelectPos & ~0xf); + FilePos = (FilePos < SelectPos ? FilePos : (FilePos > 16 ? FilePos-16 : 0)); } - - vseek(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) + FilePos = SelectPos; + Up(1); + LeftPos = 0; + + if ( !VM.Wrap ) { - Up(); - Show(); //update OutStr - } + vseek(vString.nFilePos = FilePos, SEEK_SET); + vString.lpData[0] = L'\0'; + ReadString(&vString, (int)(SelectPos-FilePos)); - /* $ 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; + wchar_t first_found_char = L'\0'; + vgetc(&first_found_char); - if (VM.Wrap) - Length%=Width+1; //?? - - if (Length<=Width) - LeftPos=0; - - if (Length-LeftPos>Width || Length<LeftPos) - { - LeftPos=Length; - - if (LeftPos>(MAX_VIEWLINE-1) || LeftPos<0) - LeftPos=0; - else if (LeftPos>10) - LeftPos-=10; + if ( L'\r' != first_found_char && L'\n' != first_found_char ) + { + int found_offset = (int)wcslen(vString.lpData); + if ( found_offset > Width-10 ) + LeftPos = (Width <= 10 ? found_offset : found_offset + 10 - Width); + } } } - if (Flags&1) + if (0 != (flags & 1)) { AdjustSelPosition = TRUE; Show(); @@ -3276,6 +3910,7 @@ } } + int Viewer::ViewerControl(int Command,void *Param) { switch (Command) @@ -3365,7 +4000,7 @@ } else { - SelectSize = 0; + SelectSize = -1; Show(); } @@ -3476,7 +4111,6 @@ Show(); } -// LastSelPos=FilePos; return oldHex; } @@ -3488,7 +4122,7 @@ if (VM.Wrap) LeftPos = 0; - if (!VM.Wrap) + if (!VM.Hex) AdjustFilePos(); if (isRedraw) @@ -3498,7 +4132,6 @@ } Opt.ViOpt.ViewerIsWrap=VM.Wrap; -// LastSelPos=FilePos; return oldWrap; } @@ -3513,6 +4146,9 @@ LeftPos = 0; } + if (!VM.Hex) + AdjustFilePos(); + if (isRedraw) { ChangeViewKeyBar(); @@ -3520,6 +4156,5 @@ } Opt.ViOpt.ViewerWrap=VM.WordWrap; -//LastSelPos=FilePos; return oldTypeWrap; } Index: config.cpp =================================================================== --- config.cpp (revision 6286) +++ config.cpp (working copy) @@ -595,6 +595,9 @@ {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"PersistentBlocks",&Opt.ViOpt.PersistentBlocks,0, 0}, {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"AnsiCodePageAsDefault",&Opt.ViOpt.AnsiCodePageAsDefault,1, 0}, + {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"MaxLineSize",&Opt.ViOpt.MaxLineSize,2048, 0}, + {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"SearchEditFocus",&Opt.ViOpt.SearchEditFocus,0, 0}, + {1, GeneralConfig::TYPE_INTEGER, NKeyDialog, L"EditHistory",&Opt.Dialogs.EditHistory,1, 0}, {1, GeneralConfig::TYPE_INTEGER, NKeyDialog, L"EditBlock",&Opt.Dialogs.EditBlock,0, 0}, {1, GeneralConfig::TYPE_INTEGER, NKeyDialog, L"AutoComplete",&Opt.Dialogs.AutoComplete,1, 0}, @@ -920,8 +923,15 @@ } } - Opt.ViOpt.ViewerIsWrap&=1; - Opt.ViOpt.ViewerWrap&=1; + Opt.ViOpt.ViewerIsWrap &= 1; + Opt.ViOpt.ViewerWrap &= 1; + if (!Opt.ViOpt.MaxLineSize) + Opt.ViOpt.MaxLineSize = 2048; + else if (Opt.ViOpt.MaxLineSize < 80) + Opt.ViOpt.MaxLineSize = 80; + else if (Opt.ViOpt.MaxLineSize > 16*1024) + Opt.ViOpt.MaxLineSize = 16*1024; + Opt.ViOpt.SearchEditFocus &= 1; // ������� �������� �������� ������������ ;-) if (Opt.strWordDiv.IsEmpty()) Index: config.hpp =================================================================== --- config.hpp (revision 6286) +++ config.hpp (working copy) @@ -314,6 +314,8 @@ int AnsiCodePageAsDefault; int ShowTitleBar; int SearchRegexp; + int MaxLineSize; // 80..16384, default=2048 + int SearchEditFocus; // auto-focus on edit text/hex window }; // "�����" |
|
+2 небольших испоавления ooops... одно лишнее |
|
NewViewer3.diff (93,452 bytes)
Index: viewer.hpp =================================================================== --- viewer.hpp (revision 6286) +++ viewer.hpp (working copy) @@ -40,22 +40,13 @@ #include "config.hpp" #include "cache.hpp" -/* $ 10.07.2000 tran - ! modified MAXSCRY from 120 to 300 - on win200, with Console height FAR work, but trap on viewer... */ -#define MAXSCRY 300 +#define MAXSCRY 512 // 300 // 120 -/* $ 12.07.2000 SVS - - ��-�� �������� ���� ������ �� 0x800 ������ FAR - �� Alt-F7. �������� MAX_VIEWLINE �� 1024 (0x400) -*/ -#define MAX_VIEWLINE 0x800 // 0x400 -#define MAX_VIEWLINEB 0x80f // 0x40f +#define MAX_VIEWLINE (ViOpt.MaxLineSize+ 0) // 0x800 // 0x400 +#define MAX_VIEWLINEB (ViOpt.MaxLineSize+15) // 0x80f // 0x40f #define VIEWER_UNDO_COUNT 64 -enum {VIEW_UNWRAP=0,VIEW_WRAP=1, VIEW_WORDWRAP=2}; - class FileViewer; class KeyBar; @@ -65,7 +56,7 @@ __int64 nFilePos; __int64 nSelStart; __int64 nSelEnd; - int nbytes; + int linesize; bool bSelection; bool have_eol; }; @@ -76,12 +67,6 @@ __int64 UndoLeft; }; -enum SEARCH_FLAGS -{ - SEARCH_MODE2 = 0x00000001, - REVERSE_SEARCH = 0x00000002 -}; - enum SHOW_MODES { SHOW_RELOAD, @@ -95,9 +80,6 @@ friend class FileViewer; private: - - BitFlags SearchFlags; - struct ViewerOptions ViOpt; bool Signature; @@ -105,7 +87,7 @@ NamesList ViewNamesList; KeyBar *ViewKeyBar; - ViewerString *Strings[MAXSCRY+1]; + ViewerString **Strings; string strFileName; string strFullFileName; @@ -121,6 +103,8 @@ string strLastSearchStr; int LastSearchCase,LastSearchWholeWords,LastSearchReverse,LastSearchHex,LastSearchRegexp; + int LastSearchDirection; + __int64 StartSearchPos; struct ViewerMode VM; @@ -128,13 +112,12 @@ __int64 SecondPos; __int64 LastScrPos; __int64 FileSize; - __int64 LastSelPos; + __int64 LastSelectPos, LastSelectSize; __int64 LeftPos; __int64 LastPage; __int64 SelectPos,SelectSize; DWORD SelectFlags; - __int64 SelectPosOffSet; // ���������� �� �������� ������ ������� � ������� ����� int ShowStatusLine,HideCursor; string strTitle; @@ -165,9 +148,20 @@ char *vread_buffer; int vread_buffer_size; - wchar_t *Up_buffer; - int Up_buffer_size; + __int64 lcache_first; + __int64 lcache_last; + __int64 *lcache_lines; + int lcache_size; + int lcache_count; + int lcache_base; + bool lcache_ready; + int lcache_wrap; + int lcache_wwrap; + int lcache_width; + wchar_t *Search_buffer; + int Search_buffer_size; + ViewerString vString; unsigned char vgetc_buffer[32]; @@ -181,8 +175,9 @@ void ShowPage(int nMode); - void Up(); - int WrappedLength(wchar_t *str, int line_size); + void Up(int n); + void CacheLine(__int64 start, int length, bool have_eol); + int CacheFindUp(__int64 start); void ShowHex(); void ShowStatus(); @@ -195,17 +190,31 @@ void AdjustWidth(); void AdjustFilePos(); - void ReadString(ViewerString *pString, int MaxSize); - int CalcStrSize(const wchar_t *Str,int Length); + void ReadString(ViewerString *pString, int MaxSize, bool update_cache=true); + __int64 EndOfScreen( int line ); + __int64 BegOfScreen(); + void ChangeViewKeyBar(); + void Search(int Next,int FirstChar); - void ConvertToHex(char *SearchStr,int &SearchLength); + // + struct search_data; + // + int search_hex_forward( search_data* sd ); + int search_hex_backward( search_data* sd ); + int search_text_forward( search_data* sd ); + int search_text_backward( search_data* sd ); + int search_regex_forward( search_data* sd ); + int search_regex_backward( search_data* sd ); + int read_line(wchar_t *buf, wchar_t *tbuf, INT64 cpos, int adjust, INT64 &lpos, int &lsize); + int vread(wchar_t *Buf, int Count, wchar_t *Buf2 = nullptr); bool vseek(__int64 Offset, int Whence); __int64 vtell(); bool vgetc(wchar_t *ch); bool veof(); + wchar_t vgetc_prev(); void SetFileSize(); int GetStrBytesNum(const wchar_t *Str, int Length); @@ -283,5 +292,5 @@ int ProcessWrapMode(int newMode, bool isRedraw=TRUE); int ProcessTypeWrapMode(int newMode, bool isRedraw=TRUE); - void SearchTextTransform(UnicodeString &to, const wchar_t *from, bool hex2text); + void SearchTextTransform(UnicodeString &to, const wchar_t *from, bool hex2text, int &pos); }; Index: viewer.cpp =================================================================== --- viewer.cpp (revision 6286) +++ viewer.cpp (working copy) @@ -65,18 +65,20 @@ #include "constitle.hpp" #include "console.hpp" #include "wakeful.hpp" +#include "RegExp.hpp" static void PR_ViewerSearchMsg(); -static void ViewerSearchMsg(const wchar_t *Name,int Percent); +static void ViewerSearchMsg(const wchar_t *name, int percent, int search_hex); -static int InitHex=FALSE,SearchHex=FALSE; +//static int InitHex=FALSE,SearchHex=FALSE; static int ViewerID=0; static int utf8_to_WideChar(const char *s, int nc, wchar_t *w1,wchar_t *w2, int wlen, int &tail); -#define REPLACE_CHAR 0xFFFD // Replacement +#define REPLACE_CHAR 0xFFFD // Replacement #define CONTINUE_CHAR 0x203A // Single Right-Pointing Angle Quotation Mark +#define BOM_CHAR 0xFEFF // Zero Length Space Viewer::Viewer(bool bQuickView, UINT aCodePage): ViOpt(Opt.ViOpt), @@ -85,10 +87,11 @@ { _OT(SysLog(L"[%p] Viewer::Viewer()", this)); - for (int i=0; i<=MAXSCRY; i++) + Strings = new ViewerString*[MAXSCRY+1]; + for (int i=0; i <= MAXSCRY; i++) { Strings[i] = new ViewerString(); - Strings[i]->lpData = new wchar_t[MAX_VIEWLINEB]; + memset(Strings[i], 0, sizeof(ViewerString)); } strLastSearchStr = strGlobalSearchString; @@ -97,19 +100,21 @@ LastSearchWholeWords=GlobalSearchWholeWords; LastSearchReverse=GlobalSearchReverse; LastSearchHex=GlobalSearchHex; + LastSearchDirection = GlobalSearchReverse ? -1 : +1; + StartSearchPos = 0; VM.CodePage=DefCodePage=aCodePage; // �������� ��� ����� VM.Wrap=Opt.ViOpt.ViewerIsWrap; VM.WordWrap=Opt.ViOpt.ViewerWrap; - VM.Hex=InitHex; + VM.Hex = FALSE; //InitHex; ViewKeyBar=nullptr; FilePos=0; LeftPos=0; SecondPos=0; FileSize=0; LastPage=0; - SelectPos=SelectSize=0; - LastSelPos=0; + SelectPos = 0; SelectSize = -1; + LastSelectPos = 0; LastSelectSize = -1; SetStatusMode(TRUE); HideCursor=TRUE; DeleteFolder=TRUE; @@ -123,7 +128,6 @@ CtrlObject->Plugins.CurViewer=this; OpenFailed=false; HostFileViewer=nullptr; - SelectPosOffSet=0; bVE_READ_Sent = false; Signature = false; @@ -132,8 +136,17 @@ vgetc_composite = L'\0'; vread_buffer = new char[vread_buffer_size = 8192]; - Up_buffer = new wchar_t[Up_buffer_size = 2 * (3*MAX_VIEWLINE + 2)]; + lcache_first = lcache_last = -1; + lcache_lines = new INT64[lcache_size = 8*1000]; + lcache_count = 0; + lcache_base = 0; + lcache_ready = false; + lcache_wrap = lcache_wwrap = lcache_width = -1; + + Search_buffer_size = 3 * (MAX_VIEWLINEB < 8000 ? 8000 : MAX_VIEWLINEB); + Search_buffer = new wchar_t[Search_buffer_size]; + memset(&vString, 0, sizeof(vString)); vString.lpData = new wchar_t[MAX_VIEWLINEB]; } @@ -169,7 +182,8 @@ } delete[] vString.lpData; - delete[] Up_buffer; + delete[] Search_buffer; + delete[] lcache_lines; delete[] vread_buffer; _tran(SysLog(L"[%p] Viewer::~Viewer, TempViewName=[%s]",this,TempViewName)); @@ -192,11 +206,13 @@ } } - for (int i=0; i<=MAXSCRY; i++) + for (int i=MAXSCRY; i >= 0; --i) { - delete [] Strings[i]->lpData; + if (Strings[i]->lpData) + delete[] Strings[i]->lpData; delete Strings[i]; } + delete[] Strings; if (!OpenFailed && bVE_READ_Sent) { @@ -216,7 +232,7 @@ Opt.ViOpt.ViewerIsWrap=VM.Wrap; Opt.ViOpt.ViewerWrap=VM.WordWrap; Opt.ViOpt.SearchRegexp=LastSearchRegexp; - InitHex=VM.Hex; + //InitHex=VM.Hex; } @@ -229,7 +245,7 @@ ViewFile.Close(); Reader.Clear(); - SelectSize = 0; // ������� �������� + SelectSize = -1; // ������� �������� strFileName = Name; if (Opt.OnlyEditorViewerUsed && !StrCmp(strFileName, L"-")) @@ -302,7 +318,7 @@ // �������� ������������� ��� ��� ���������� �� �� ������ ������� if (CachedCodePage && !IsCodePageSupported(CachedCodePage)) CachedCodePage = 0; - LastSelPos=FilePos=NewFilePos; + LastSelectPos=FilePos=NewFilePos; LeftPos=NewLeftPos; } else @@ -350,19 +366,13 @@ CodePageChangedByUser=TRUE; } - if (!IsUnicodeOrUtfCodePage(VM.CodePage)) - { - ViewFile.SetPointer(0, nullptr, FILE_BEGIN); - } + ViewFile.SetPointer(0, nullptr, FILE_BEGIN); } SetFileSize(); - if (FilePos>FileSize) + if (FilePos > FileSize) FilePos=0; -// if (ViOpt.AutoDetectTable && !TableChangedByUser) -// { -// } ChangeViewKeyBar(); AdjustWidth(); CtrlObject->Plugins.CurViewer=this; // HostFileViewer; @@ -379,12 +389,12 @@ DriveType = DRIVE_CDROM; switch (DriveType) //??? make it configurable { - case DRIVE_REMOVABLE: update_check_period = -1; break; // flash drive or floppy: never - case DRIVE_FIXED: update_check_period = +1; break; // hard disk: 1msec - case DRIVE_REMOTE: update_check_period = 1000; break; // network drive: 1sec - case DRIVE_CDROM: update_check_period = -1; break; // cd/dvd: never - case DRIVE_RAMDISK: update_check_period = +1; break; // ramdrive: 1msec - default: update_check_period = -1; break; // unknown: never + case DRIVE_REMOVABLE: update_check_period = -1; break; // flash drive or floppy: never + case DRIVE_FIXED: update_check_period = +1; break; // hard disk: 1 msec + case DRIVE_REMOTE: update_check_period = 500; break; // network drive: 0.5 sec + case DRIVE_CDROM: update_check_period = -1; break; // cd/dvd: never + case DRIVE_RAMDISK: update_check_period = +1; break; // ramdrive: 1 msec + default: update_check_period = -1; break; // unknown: never } return TRUE; @@ -428,8 +438,9 @@ SetCursorType(0,10); vseek(FilePos,SEEK_SET); + LastPage = 0; - if (!SelectSize) + if ( SelectSize < 0 ) SelectPos=FilePos; switch (nMode) @@ -471,7 +482,7 @@ } FilePos = Strings[0]->nFilePos; SecondPos = Strings[1]->nFilePos; - Strings[Y2-Y1]->nFilePos = Strings[Y2-Y1-1]->nFilePos + Strings[Y2-Y1-1]->nbytes; + Strings[Y2-Y1]->nFilePos = Strings[Y2-Y1-1]->nFilePos + Strings[Y2-Y1-1]->linesize; vseek(Strings[Y2-Y1]->nFilePos, SEEK_SET); ReadString(Strings[Y2-Y1],-1); break; @@ -487,21 +498,14 @@ if (StrLen > LeftPos) { - if (IsUnicodeOrUtfCodePage(VM.CodePage) && Signature && !I && !Strings[I]->nFilePos) - { - FS<<fmt::LeftAlign()<<fmt::Width(Width)<<fmt::Precision(Width)<<&Strings[I]->lpData[static_cast<size_t>(LeftPos+1)]; - } - else - { - FS<<fmt::LeftAlign()<<fmt::Width(Width)<<fmt::Precision(Width)<<&Strings[I]->lpData[static_cast<size_t>(LeftPos)]; - } + FS<<fmt::LeftAlign()<<fmt::Width(Width)<<fmt::Precision(Width)<<&Strings[I]->lpData[static_cast<size_t>(LeftPos)]; } else { FS<<fmt::Width(Width)<<L""; } - if (SelectSize && Strings[I]->bSelection) + if ( SelectSize >= 0 && Strings[I]->bSelection) { __int64 SelX1; @@ -532,7 +536,7 @@ if (LeftPos > Strings[I]->nSelEnd) Length = 0; - FS<<fmt::Precision(static_cast<int>(Length))<<&Strings[I]->lpData[static_cast<size_t>(SelX1+LeftPos+SelectPosOffSet)]; + FS<<fmt::Precision(static_cast<int>(Length))<<&Strings[I]->lpData[static_cast<size_t>(SelX1+LeftPos)]; } } @@ -571,6 +575,9 @@ bool bSelStartFound = false, bSelEndFound = false; __int64 HexLeftPos=((LeftPos>80-ObjWidth) ? Max(80-ObjWidth,0):LeftPos); + const wchar_t BorderLine[] = {BoxSymbols[BS_V1],L' ',0}; + int border_len = (int)wcslen(BorderLine); + for (EndFile=0,Y=Y1; Y<=Y2; Y++) { bSelStartFound = false; @@ -588,12 +595,9 @@ if (Y==Y1+1 && !veof()) SecondPos=vtell(); - INT64 Ptr=ViewFile.GetPointer(); - _snwprintf(OutStr,ARRAYSIZE(OutStr),L"%010I64X: ", Ptr); + int out_len = _snwprintf(OutStr,ARRAYSIZE(OutStr),L"%010I64X: ", vtell()); + SelEnd = SelStart = out_len; TextPos=0; - int HexStrStart = (int)wcslen(OutStr); - SelStart = HexStrStart; - SelEnd = SelStart; __int64 fpos = vtell(); if (fpos > SelectPos) @@ -602,103 +606,108 @@ if (fpos < SelectPos+SelectSize-1) bSelEndFound = true; - if (!SelectSize) + if ( SelectSize < 0 ) bSelStartFound = bSelEndFound = false; - const wchar_t BorderLine[]={BoxSymbols[BS_V1],L' ',0}; + unsigned char line[16+3]; + DWORD nr = 0; + DWORD nb = CP_UTF8 == VM.CodePage ? 16+3 : 16; + Reader.Read(line, nb, &nr); + if (nr > 16) + Reader.Unread(nr-16); - int out_len = (int)wcslen(OutStr); - int border_len = (int)wcslen(BorderLine); + LastPage = EndFile = (nr <= nb) && veof() ? 1 : 0; - if (IsUnicodeCodePage(VM.CodePage)) + if (nr <= 0) { - wchar_t line[8]; - int nr = vread(line, 8); - LastPage = EndFile = veof() ? 1 : 0; - if (nr <= 0) + *OutStr = L'\0'; + } + else + { + if (IsUnicodeCodePage(VM.CodePage)) { - *OutStr = L'\0'; - } - else - { - for (X=0; X<8; X++) + int be = VM.CodePage == CP_REVERSEBOM ? 1 : 0; + for (X=0; X<16; X += 2) { - if (SelectSize>0 && (SelectPos == fpos)) + if (SelectSize >= 0 && (SelectPos == fpos || SelectPos == fpos+1)) { + bool half = SelectPos != fpos; bSelStartFound = true; - SelStart = (int)wcslen(OutStr); - SelSize=SelectSize; + SelStart = out_len + (half ? 1+be : 0); + if ( 0 == (SelSize=SelectSize) ) + SelStart += (half ? be : 0) - 1; } - if (SelectSize>0 && (fpos == (SelectPos+SelectSize-1))) + if (SelectSize >= 0 && (fpos == SelectPos+SelectSize-1 || fpos+1 == SelectPos+SelectSize-1)) { + bool half = fpos == SelectPos+SelectSize-1; bSelEndFound = true; - SelEnd = (int)wcslen(OutStr)+3; - SelSize=SelectSize; + SelEnd = out_len+3 - (half ? 1+be : 0); + if ( 0 == (SelSize=SelectSize) ) + SelEnd = SelStart; } + else if ( SelectSize == 0 && (SelectPos == fpos || SelectPos == fpos+1) ) + { + bSelEndFound = true; + SelSize = 0; + SelEnd = SelStart; + } - if (X < nr) + if ((DWORD)X < nr-1) // full character { - unsigned char b1 = HIBYTE(line[X]), b2 = LOBYTE(line[X]); -#if 0 // !!! ��������� �������� !!! - if (VM.CodePage != CP_REVERSEBOM) // ��� ������ � ���� ���� - { // ������� �������� ������������� ��� - unsigned char t = b1; b1 = b2; b2 = t; - } -#endif - _snwprintf(OutStr+out_len, ARRAYSIZE(OutStr)-out_len, L"%02X%02X ", b1, b2); - TextStr[TextPos++] = line[X] ? line[X] : L' '; + unsigned ch = line[X+be] + (line[X+1-be] << 8); + _snwprintf(OutStr+out_len, ARRAYSIZE(OutStr)-out_len, L"%04X ", ch); + TextStr[TextPos++] = ch ? (wchar_t)ch : L' '; } - else + else if ((DWORD)X == nr-1) // half character only { + int o1 = 2 * (1 - be); + _snwprintf(OutStr+out_len+o1, ARRAYSIZE(OutStr)-out_len-o1, L"%02X", line[X]); + OutStr[out_len+2-o1] = OutStr[out_len+2-o1+1] = L'x'; + OutStr[out_len+4] = L' '; + TextStr[TextPos++] = REPLACE_CHAR; + } + else // no character + { wcscpy(OutStr+out_len, L" "); TextStr[TextPos++] = L' '; } out_len += 5; - if (X == 3) + if (X == 3*2) { wcscpy(OutStr+out_len, BorderLine); out_len += border_len; } - ++fpos; + fpos += 2; } } - } - else - { - unsigned char line[16+3]; - DWORD nr = 0; - DWORD nb = CP_UTF8 == VM.CodePage ? 16+3 : 16; - Reader.Read(line, nb, &nr); - if (nr > 16) - Reader.Unread(nr-16); - - LastPage = EndFile = (nr <= nb) && veof() ? 1 : 0; - - if (!nr) - { - *OutStr = L'\0'; - } else { - if (SelectSize) + if ( SelectSize >= 0 ) { if (SelectPos >= fpos && SelectPos < fpos+16) { int off = (int)(SelectPos - fpos); bSelStartFound = true; SelStart = out_len + 3*off + (off < 8 ? 0 : border_len); - SelSize = SelectSize; + if ( 0 == (SelSize=SelectSize) ) + --SelStart; } __int64 selectEnd = SelectPos + SelectSize - 1; if (selectEnd >= fpos && selectEnd < fpos+16) { int off = (int)(selectEnd - fpos); bSelEndFound = true; - SelEnd = out_len + 3*off + (off < 8 ? 0 : border_len) + 1; - SelSize = SelectSize; + SelEnd = (0 == (SelSize=SelectSize) ? SelStart : out_len + 3*off + (off < 8 ? 0 : border_len) + 1); } + else if ( SelectSize == 0 && SelectPos == fpos ) + { + bSelEndFound = true; + SelSize = 0; + SelEnd = SelStart; + } } + for (X=0; X<16; X++) { int off = out_len + 3*X + (X < 8 ? 0 : border_len); @@ -712,6 +721,7 @@ if (CP_UTF8 != VM.CodePage && X < (int)nr && line[X]) MultiByteToWideChar(VM.CodePage, 0, (LPCSTR)line+X, 1, TextStr+X, 1); } + out_len += 3*16 + border_len; if (CP_UTF8 == VM.CodePage) { @@ -730,7 +740,7 @@ first = false; TextStr[ib++] = w1[iw] ? w1[iw] : L' '; } - int clen = WideCharToMultiByte(CP_UTF8, 0, w2+iw, 1, nullptr, 0, nullptr, nullptr); + int clen = WideCharToMultiByte(CP_UTF8, 0, w2+iw, 1, NULL,0, NULL,NULL); while (--clen > 0 && ib < 16) TextStr[ib++] = CONTINUE_CHAR; ++iw; @@ -740,14 +750,14 @@ } } - TextStr[TextPos]=0; - wcscat(TextStr,L" "); + TextStr[TextPos] = L' '; + TextStr[TextPos+1] = L'\0'; - if ((SelEnd <= SelStart) && bSelStartFound) - SelEnd = (int)wcslen(OutStr)-2; + if ((SelEnd <= SelStart) && bSelStartFound && bSelEndFound && SelectSize > 0 ) + SelEnd = out_len-2; - wcscat(OutStr,L" "); - wcscat(OutStr,TextStr); + OutStr[out_len] = L' '; + wcscpy(OutStr+out_len+1, TextStr); if (StrLength(OutStr)>HexLeftPos) { @@ -789,7 +799,7 @@ { 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); + ScrollBarEx(X2+(m_bQuickView?1:0),Y1,Y2-Y1+1,LastPage?Top?Total:0:Top,Total); } } } @@ -837,6 +847,15 @@ return L'\0' == ch || IsSpace(ch); } +static bool is_word_div ( const wchar_t ch ) +{ + static const wchar_t spaces[] = { L' ', L'\t', L'\n', L'\r', BOM_CHAR, REPLACE_CHAR, L'\0' }; + return ( !ch + || nullptr != wcschr(spaces, ch) + || nullptr != wcschr(Opt.strWordDiv, ch) + ); +} + static inline int wrapped_char( const wchar_t ch ) { static const wchar_t wrapped_chars[] = L",;>)"; // word-wrap enabled after it @@ -849,18 +868,31 @@ return -1; } -void Viewer::ReadString(ViewerString *pString, int MaxSize) +static inline int getCharSize( UINT cp ) { + if ( CP_UTF8 == cp ) + return -1; + else if ( CP_UNICODE == cp || CP_REVERSEBOM == cp ) + return +2; + else + return +1; +} + +void Viewer::ReadString( ViewerString *pString, int MaxSize, bool update_cache ) +{ AdjustWidth(); int OutPtr = 0, nTab = 0, wrap_out = -1; wchar_t ch, eol_char = L'\0'; - __int64 fpos, sel_end, wrap_pos = -1; + INT64 fpos=0, fpos1, sel_end, wrap_pos = -1; bool skip_space = false; + if ( !pString->lpData ) + pString->lpData = new wchar_t[MAX_VIEWLINEB]; + if (VM.Hex) { - vseek(IsUnicodeCodePage(VM.CodePage) ? 8 : 16, FILE_CURRENT); + vseek(16, FILE_CURRENT); pString->lpData[OutPtr] = L'\0'; LastPage = veof(); return; @@ -869,10 +901,12 @@ bool bSelStartFound = false, bSelEndFound = false; pString->bSelection = false; sel_end = SelectPos + SelectSize; - fpos = vtell(); + fpos1 = vtell(); for (;;) { + fpos = fpos1; + if (OutPtr >= MAX_VIEWLINE) break; @@ -880,27 +914,31 @@ ch = L' '; else { - fpos = vtell(); if (!MaxSize-- || !vgetc(&ch)) break; } + fpos1 = vtell(); - if (SelectSize > 0) + if (SelectSize >= 0) { - if (fpos == SelectPos) + if (fpos == SelectPos || (fpos < SelectPos && fpos1 > SelectPos)) { pString->nSelStart = OutPtr; bSelStartFound = true; } - if (fpos == sel_end) + if (fpos == sel_end || (fpos < sel_end && fpos1 > sel_end)) { - pString->nSelEnd = OutPtr; + pString->nSelEnd = OutPtr + (fpos < sel_end ? 1 : 0); bSelEndFound = true; } } - if (L'\t' == ch) + if (!fpos && BOM_CHAR == ch) { + continue; // skip BOM + } + else if (L'\t' == ch) + { nTab = ViOpt.TabSize - (OutPtr % ViOpt.TabSize); continue; } @@ -913,7 +951,7 @@ pString->lpData[OutPtr++] = ch ? ch : L' '; if (!VM.Wrap) continue; - + if (OutPtr >= Width) { if (VM.WordWrap && wrap_out > 0) @@ -965,9 +1003,12 @@ pString->have_eol = (eol_char != L'\0'); pString->lpData[(int)OutPtr]=0; - pString->nbytes = (int)(vtell() - pString->nFilePos); + pString->linesize = (int)(vtell() - pString->nFilePos); - if (SelectSize > 0 && OutPtr > 0) + if ( update_cache ) + CacheLine(pString->nFilePos, pString->linesize, pString->have_eol); + + if (SelectSize >= 0 && OutPtr > 0) { if (!bSelStartFound && pString->nFilePos >= SelectPos && pString->nFilePos <= sel_end) { @@ -987,8 +1028,86 @@ if (!eol_char && veof()) LastPage = 1; +} + + +__int64 Viewer::EndOfScreen( int line ) +{ + __int64 pos; + + if (!VM.Hex) + { + pos = Strings[Y2-Y1+line]->nFilePos + Strings[Y2-Y1+line]->linesize; + if ( !line && !VM.Wrap && Strings[Y2-Y1]->linesize > 0 ) + { + vseek(Strings[Y1-Y2]->nFilePos, SEEK_SET); + int col = 0, rmargin = (int)LeftPos + Width; + wchar_t ch; + for (;;) + { + if ( !vgetc(&ch) ) + break; + if ( ch == L'\n' || ch == L'\r' ) + break; + if ( ch == L'\t' ) + col += ViOpt.TabSize - (col % ViOpt.TabSize); + else + ++col; + if ( col >= rmargin ) + { + pos = vtell(); + break; + } + } + } + } + else + pos = FilePos + 16 * (Y2-Y1+1+line); + + if (pos < 0) + pos = 0; + else if (pos > FileSize) + pos = FileSize; + + return pos; } + +__int64 Viewer::BegOfScreen() +{ + __int64 pos = FilePos, prev_pos; + + if (!VM.Hex && !VM.Wrap && LeftPos > 0) + { + vseek(FilePos, SEEK_SET); + int col = 0; + wchar_t ch; + pos = -1; + for (;;) + { + prev_pos = vtell(); + if ( !vgetc(&ch) ) + break; + if ( ch == L'\n' || ch == L'\r' ) + { + pos = Strings[1]->nFilePos; + break; + } + if ( ch == L'\t' ) + col += ViOpt.TabSize - (col % ViOpt.TabSize); + else + ++col; + if ( col > LeftPos ) //!! ������ �������� ����� ������ + break; //!! ��� LeftPos=1 �� ���� 2 ������� + } + if ( pos < 0 ) + pos = (col > LeftPos ? prev_pos : vtell()); + } + + return pos; +} + + __int64 Viewer::VMProcess(int OpCode,void *vParam,__int64 iParam) { switch (OpCode) @@ -996,7 +1115,7 @@ case MCODE_C_EMPTY: return (__int64)!FileSize; case MCODE_C_SELECTED: - return (__int64)(SelectSize?TRUE:FALSE); + return (__int64)(SelectSize >= 0 ?TRUE:FALSE); case MCODE_C_EOF: return (__int64)(LastPage || !ViewFile.Opened()); case MCODE_C_BOF: @@ -1030,7 +1149,7 @@ */ if (!ViOpt.PersistentBlocks && Key!=KEY_IDLE && Key!=KEY_NONE && !(Key==KEY_CTRLINS||Key==KEY_CTRLNUMPAD0) && Key!=KEY_CTRLC) - SelectSize=0; + SelectSize = -1; if (!InternalKey && !LastKeyUndo && (FilePos!=UndoData[0].UndoAddr || LeftPos!=UndoData[0].UndoLeft)) { @@ -1055,7 +1174,6 @@ { FilePos=BMSavePos.FilePos[Pos]; LeftPos=BMSavePos.LeftPos[Pos]; -// LastSelPos=FilePos; Show(); } @@ -1082,25 +1200,20 @@ } case KEY_CTRLU: { -// if (SelectSize) - { - SelectSize = 0; - Show(); - } + SelectSize = -1; + Show(); return TRUE; } case KEY_CTRLC: case KEY_CTRLINS: case KEY_CTRLNUMPAD0: { - if (SelectSize && ViewFile.Opened()) + if (SelectSize >= 0 && ViewFile.Opened()) { - wchar_t *SelData; - size_t DataSize = (size_t)SelectSize+(IsUnicodeCodePage(VM.CodePage)?sizeof(wchar_t):1); - __int64 CurFilePos=vtell(); - - if ((SelData=(wchar_t*)xf_malloc(DataSize*sizeof(wchar_t))) ) + wchar_t *SelData = (wchar_t*)xf_malloc((size_t)SelectSize+1); + if ( SelData ) { - wmemset(SelData, 0, DataSize); + __int64 CurFilePos=vtell(); + wmemset(SelData, 0, (size_t)SelectSize+1); vseek(SelectPos,SEEK_SET); vread(SelData, (int)SelectSize); CopyToClipboard(SelData); @@ -1108,7 +1221,6 @@ vseek(CurFilePos,SEEK_SET); } } - return TRUE; } // �����/����� �������� @@ -1145,6 +1257,8 @@ Reader.Clear(); // ���� ���� �� ��� ����? ViewFile.FlushBuffers(); + vseek(0, SEEK_CUR); // reset vgetc state + lcache_ready = false; // reset start-lines cache if (FilePos>FileSize) { @@ -1251,19 +1365,16 @@ } case KEY_SHIFTF2: { - LastPage = 0; ProcessTypeWrapMode(!VM.WordWrap); return TRUE; } case KEY_F2: { - LastPage = 0; ProcessWrapMode(!VM.Wrap); return TRUE; } case KEY_F4: { - LastPage = 0; ProcessHexMode(!VM.Hex); return TRUE; } @@ -1280,23 +1391,13 @@ } case KEY_ALTF7: { - SearchFlags.Set(REVERSE_SEARCH); - Search(1,0); - SearchFlags.Clear(REVERSE_SEARCH); + Search(-1,0); return TRUE; } case KEY_F8: { - LastPage = 0; - if (IsUnicodeCodePage(VM.CodePage)) - { - FilePos*=2; - SetFileSize(); - SelectPos = 0; - SelectSize = 0; - } - VM.CodePage = VM.CodePage==GetOEMCP() ? GetACP() : GetOEMCP(); + lcache_ready = false; ChangeViewKeyBar(); Show(); CodePageChangedByUser=TRUE; @@ -1304,12 +1405,12 @@ } case KEY_SHIFTF8: { - LastPage = 0; UINT nCodePage = SelectCodePage(VM.CodePage, true, true, false, true); + lcache_ready = false; - if (nCodePage!=(UINT)-1) + if (nCodePage != static_cast<UINT>(-1)) { - if (nCodePage == (WORD)(CP_AUTODETECT & 0xffff)) + if (nCodePage == (CP_AUTODETECT & 0xffff)) { __int64 fpos = vtell(); bool detect = GetFileFormat(ViewFile,nCodePage,&Signature,true) && IsCodePageSupported(nCodePage); @@ -1318,20 +1419,6 @@ nCodePage = Opt.ViOpt.AnsiCodePageAsDefault ? GetACP() : GetOEMCP(); } CodePageChangedByUser=TRUE; - - if (IsUnicodeCodePage(VM.CodePage) && !IsUnicodeCodePage(nCodePage)) - { - FilePos*=2; - SelectPos = 0; - SelectSize = 0; - } - else if (!IsUnicodeCodePage(VM.CodePage) && IsUnicodeCodePage(nCodePage)) - { - FilePos=(FilePos+(FilePos&1))/2; //???? - SelectPos = 0; - SelectSize = 0; - } - VM.CodePage=nCodePage; SetFileSize(); ChangeViewKeyBar(); @@ -1402,11 +1489,10 @@ { if (FilePos>0 && ViewFile.Opened()) { - Up(); // LastPage = 0 + Up(1); // LastPage = 0 if (VM.Hex) { - //FilePos&=~(IsUnicodeCodePage(VM.CodePage) ? 0x7:0xf); Show(); } else @@ -1414,7 +1500,7 @@ ShowPage(SHOW_UP); ViewerString *end = Strings[Y2-Y1]; LastPage = end->nFilePos >= FileSize || - (!end->have_eol && end->nFilePos + end->nbytes >= FileSize); + (!end->have_eol && end->nFilePos + end->linesize >= FileSize); } } @@ -1439,9 +1525,7 @@ { if (ViewFile.Opened()) { - for (int i=Y1; i<Y2; i++) - Up(); - + Up(Y2-Y1); Show(); } @@ -1452,25 +1536,25 @@ if (LastPage || !ViewFile.Opened()) return TRUE; - if (VM.Hex) - FilePos += (IsUnicodeCodePage(VM.CodePage) ? 8 : 16) * (Y2-Y1); - else - FilePos = Strings[Y2-Y1]->nFilePos; + FilePos = EndOfScreen(-1); // start of last screen line if (Key == KEY_CTRLDOWN) { - vseek(FilePos, SEEK_SET); + vseek(vString.nFilePos = FilePos, SEEK_SET); for (int i=Y1; i<=Y2; i++) - ReadString(&vString,-1); + { + ReadString(&vString,-1); + vString.nFilePos += vString.linesize; + } if (LastPage) - { - InternalKey++; - ProcessKey(KEY_CTRLPGDN); - InternalKey--; - return TRUE; + { + InternalKey++; + ProcessKey(KEY_CTRLPGDN); + InternalKey--; + return TRUE; + } } - } Show(); return TRUE; @@ -1504,17 +1588,11 @@ { if (VM.Hex) { - FilePos--; - - if (FilePos<0) - FilePos=0; + FilePos = FilePos > 0 ? FilePos-1 : 0; } else { - LeftPos-=20; - - if (LeftPos<0) - LeftPos=0; + LeftPos = LeftPos > 20 ? LeftPos-20 : 0; } Show(); @@ -1528,10 +1606,7 @@ { if (VM.Hex) { - FilePos++; - - if (FilePos >= FileSize) - FilePos=FileSize-1; //?? + FilePos = FilePos < FileSize-1 ? FilePos+1 : FileSize-1; } else if (!VM.Wrap) { @@ -1592,7 +1667,6 @@ if (ViewFile.Opened()) { FilePos=0; - LastPage = 0; Show(); } @@ -1614,32 +1688,33 @@ ��������� End (� ������) �� ����� ������ �������� �� ��������� Down. */ - unsigned int max_counter=Y2-Y1; + int max_counter = Y2 - Y1; if (VM.Hex) { vseek(0,SEEK_END); FilePos = vtell(); - int line_chars = IsUnicodeCodePage(VM.CodePage) ? 8 : 16; - if ((FilePos % line_chars) == 0) - FilePos -= line_chars * (Y2 - Y1 + 1); + if ((FilePos % 16) == 0) + FilePos -= 16 * (Y2 - Y1 + 1); else - FilePos -= (FilePos % line_chars) + line_chars * (Y2 - Y1); + FilePos -= (FilePos % 16) + 16 * (Y2 - Y1); if (FilePos < 0) FilePos = 0; } else { - vseek(-1,SEEK_END); - WCHAR LastSym=0; + int ch_size = getCharSize(VM.CodePage); + wchar_t LastSym = L'\0'; - if (vgetc(&LastSym) && LastSym!=L'\n' && LastSym!=L'\r') + vseek(0, SEEK_END); + FilePos = vtell() - 1; + FilePos -= FilePos % ch_size; + vseek(FilePos, SEEK_SET); + if (vgetc(&LastSym) && LastSym != L'\n' && LastSym != L'\r') ++max_counter; FilePos=vtell(); - - for (int i=0; static_cast<unsigned int>(i)<max_counter; i++) - Up(); + Up(max_counter); } Show(); @@ -1688,7 +1763,7 @@ { while (IsMouseButtonPressed()) { -// _SVS(SysLog(L"Viewer/ KEY_DOWN= %i, %i",FilePos,FileSize)); + //_SVS(SysLog(L"Viewer/ KEY_DOWN= %i, %i",FilePos,FileSize)); ProcessKey(KEY_DOWN); } } @@ -1719,7 +1794,7 @@ else Perc=ToPercent64(FilePos,FileSize); -//_SVS(SysLog(L"Viewer/ ToPercent()=%i, %I64d, %I64d, Mouse=[%d:%d]",Perc,FilePos,FileSize,MsX,MsY)); + //_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) @@ -1796,140 +1871,270 @@ return TRUE; } -void Viewer::Up() + +void Viewer::CacheLine( __int64 start, int length, bool have_eol ) { - if (!ViewFile.Opened()) + assert(start >= 0 && length >= 0); + if (!length) // empty lines beyond EOF return; - LastPage = 0; + if ( lcache_ready + && (lcache_wrap != VM.Wrap || lcache_wwrap != VM.WordWrap || lcache_width != Width) + ){ + lcache_ready = false; + } - if (FilePos <= 0) - return; - - if (VM.Hex) + if (!lcache_ready || start > lcache_last || start+length < lcache_first) { - FilePos -= IsUnicodeCodePage(VM.CodePage) ? 8 : 16; - if (FilePos < 0) - FilePos = 0; - return; - } + lcache_first = start; + lcache_last = start + length; - int Skipped = 0, I = -1, BufSize = MAX_VIEWLINE + 2; - wchar_t *Buf = Up_buffer, *tBuf = Up_buffer, *tBuf2 = nullptr; + lcache_count = 2; + lcache_base = 0; + lcache_lines[0] = (have_eol ? -start : +start); + lcache_lines[1] = start + length; - if (!VM.Hex && VM.CodePage == CP_UTF8) - { - BufSize = Up_buffer_size / 2; // = 3*MAXLINE + 2; - tBuf = tBuf2 = Up_buffer + BufSize; + lcache_wrap = VM.Wrap; lcache_wwrap = VM.WordWrap; lcache_width = Width; + lcache_ready = true; } - - if (FilePos < (__int64)BufSize) - BufSize = (int)FilePos; - - if (BufSize >= 512) // first try to find newline in first 256 bytes + else if (start == lcache_last) { - vseek(FilePos-256, SEEK_SET); - int nr = vread(Buf, 256, tBuf2); - - if (nr > 0 && Buf[nr-1] == L'\n') + int i = (lcache_base + lcache_count - 1) % lcache_size; + lcache_lines[i] = (have_eol ? -start : +start); + i = (i + 1) % lcache_size; + lcache_lines[i] = lcache_last = start + length; + if (lcache_count < lcache_size) + ++lcache_count; + else { - --nr; ++Skipped; + lcache_base = (lcache_base + 1) % lcache_size; // ++start + lcache_first = _abs64(lcache_lines[lcache_base]); } - if (nr > 0 && Buf[nr-1] == L'\r') + } + else if (start+length == lcache_first) + { + lcache_base = (lcache_base + lcache_size - 1) % lcache_size; // --start + lcache_lines[lcache_base] = (have_eol ? -start : +start); + lcache_first = start; + if (lcache_count < lcache_size) + ++lcache_count; + else { - --nr; ++Skipped; + int i = (lcache_base + lcache_size - 1) % lcache_size; // i = start - 1 + lcache_last = _abs64(lcache_lines[i]); } + } + else + { +#if defined(_DEBUG) && 1 // it is legal case if file changed... + assert(start >= lcache_first && start+length <= lcache_last); + int i = CacheFindUp(start+length); + assert(i >= 0 && _abs64(lcache_lines[i]) == start); +#endif + lcache_first = start; + lcache_last = start + length; - for (I = nr-1; I >= 0; I--) - { - if (Buf[I] == L'\n' || Buf[I] == L'\r') - { - BufSize = nr; - break; - } - } + lcache_count = 2; + lcache_base = 0; + lcache_lines[0] = (have_eol ? -start : +start); + lcache_lines[1] = start + length; } +} - if (I < 0) // full portion read +int Viewer::CacheFindUp( __int64 start ) +{ + if ( lcache_ready + && (lcache_wrap != VM.Wrap || lcache_wwrap != VM.WordWrap || lcache_width != Width) + ){ + lcache_ready = false; + } + if ( !lcache_ready || start <= lcache_first || start > lcache_last ) + return -1; + + int i, j, i1 = 0, i2 = lcache_count - 1; + for (;;) { - vseek(FilePos - BufSize, SEEK_SET); - BufSize = vread(Buf, BufSize, tBuf2); - Skipped=0; + if ( i1+1 >= i2 ) + return (lcache_base + i1) % lcache_size; - if (BufSize > 0 && Buf[BufSize-1]==L'\n') - { - --BufSize; ++Skipped; - } - if (BufSize > 0 && Buf[BufSize-1] == L'\r') - { - --BufSize; ++Skipped; - } - - int I0 = BufSize > MAX_VIEWLINE ? BufSize - MAX_VIEWLINE : 0; - for (I = BufSize-1; I >= I0; I--) - { - if (Buf[I] == L'\n' || Buf[I] == L'\r') - break; - } + i = (i1 + i2) / 2; + j = (lcache_base + i) % lcache_size; + if (_abs64(lcache_lines[j]) < start) + i1 = i; + else + i2 = i; } +} - if (!VM.Wrap) +void Viewer::Up( int nlines ) +{ + assert( nlines > 0 ); + + if (!ViewFile.Opened()) + return; + + LastPage = 0; + + if (FilePos <= 0) + return; + + if (VM.Hex) { - FilePos -= GetStrBytesNum(tBuf + (I+1), BufSize-(I+1)) + Skipped; + FilePos = FilePos > 16*nlines ? FilePos-16*nlines : 0; + return; } - else + + __int64 fpos, fpos1; + + int i = CacheFindUp(fpos = FilePos); + if ( i >= 0 ) { - wchar_t *line = tBuf + I+1; - int len, line_size = BufSize - (I+1); for (;;) { - len = WrappedLength(line, line_size); - if ( len >= line_size ) + fpos = _abs64(lcache_lines[i]); + if (--nlines == 0) + { + FilePos = fpos; + return; + } + if (i == lcache_base) break; - line += len; - line_size -= len; + i = (i + lcache_size - 1) % lcache_size; } - FilePos -= GetStrBytesNum(line, line_size + Skipped); } - return; -} -int Viewer::WrappedLength(wchar_t *str, int line_size) -{ - int width = 0, off = 0, wrap_pos = -1, wrap_ch, tab_size = ViOpt.TabSize; - bool wwrap = VM.Wrap && VM.WordWrap; + static const int portion_size = 256; + static const int max_backward = 32*1024; - for (;;) + union { + char c1[portion_size]; + wchar_t c2[portion_size/(int)sizeof(wchar_t)]; + } buff; + + int j, buff_size, nr, ch_size = getCharSize(VM.CodePage); + int len[max_backward/40]; // suppose minimum line with is 80 chars... + + while ( nlines > 0 ) { - if (off >= line_size) - return off; + if ( fpos <= 0 ) + { + FilePos = 0; + return; + } - wchar_t ch = str[off++]; - width += L'\t' != ch ? 1 : tab_size - width % tab_size; + fpos1 = fpos; - if (width >= Width) + // backward CR-LF search + // + for ( j = 0; j < max_backward/portion_size; ++j ) { - if (!wwrap || wrap_pos <= 0) - return off; - while (wrap_pos < line_size && is_space_or_nul(str[wrap_pos])) - ++wrap_pos; - return wrap_pos; + buff_size = (fpos > (__int64)portion_size ? portion_size : (int)fpos); + fpos -= buff_size; + vseek(fpos, SEEK_SET); + + if ( ch_size <= 1 ) + { + DWORD nread = 0; + Reader.Read(buff.c1, static_cast<DWORD>(buff_size), &nread); + if ((nr = (int)nread) != buff_size) + { + return; //??? error handling + } + if ( 0 == j ) + { + if ( nr > 0 && '\n' == buff.c1[nr-1] ) + { + --nr; + } + if ( nr > 0 && '\r' == buff.c1[nr-1] ) + { + --nr; + } + } + for ( i = nr-1; i >= 0; --i ) + { + if ( '\n' == buff.c1[i] || '\r' == buff.c1[i] ) + break; + } + if ( i >= 0 ) + { + fpos += i + 1; + break; + } + } + else + { + nr = vread(buff.c2, buff_size); + if ( nr != buff_size / ch_size ) + { + return; //??? error handling + } + if ( 0 == j ) + { + if ( nr > 0 && L'\n' == buff.c2[nr-1] ) + { + --nr; + } + if ( nr > 0 && L'\r' == buff.c2[nr-1] ) + { + --nr; + } + } + for ( i = nr-1; i >= 0; --i ) + { + if ( L'\n' == buff.c2[i] || L'\r' == buff.c2[i] ) + break; + } + if ( i >= 0 ) + { + fpos += ch_size * (i + 1); + break; + } + } } - if (!wwrap) - continue; + // split read portion + // + vseek(vString.nFilePos = fpos, SEEK_SET); + for (i = 0; i < (int)ARRAYSIZE(len); ++i) + { + ReadString(&vString, -1, false); + len[i] = (vString.have_eol ? -1 : +1) * vString.linesize; + if ((vString.nFilePos += vString.linesize) >= fpos1) + { + fpos1 = vString.nFilePos; + break; + } + } + assert(i < (int)ARRAYSIZE(len)); + if (i >= (int)ARRAYSIZE(len)) + --i; - if ((wrap_ch = wrapped_char(ch)) >= 0) - wrap_pos = off - 1 + wrap_ch; + while ( i >= 0 ) + { + int l = len[i--]; + bool eol = false; + if (l < 0) + { + eol = true; + l = -l; + } + fpos1 -= l; + CacheLine(fpos1, l, eol); + if (--nlines == 0) + FilePos = fpos1; + } } } -int Viewer::GetStrBytesNum(const wchar_t *Str, int Length) + +int Viewer::GetStrBytesNum( const wchar_t *Str, int Length ) { - if (IsUnicodeCodePage(VM.CodePage)) - return Length; + int ch_size = getCharSize(VM.CodePage); + if (ch_size > 0) + return Length * ch_size; else - return WideCharToMultiByte(VM.CodePage, 0, Str, Length, nullptr, 0, nullptr, nullptr); + return WideCharToMultiByte(VM.CodePage,0, Str,Length, nullptr,0, nullptr,nullptr); } void Viewer::SetViewKeyBar(KeyBar *ViewKeyBar) @@ -1938,7 +2143,6 @@ ChangeViewKeyBar(); } - void Viewer::ChangeViewKeyBar() { if (ViewKeyBar) @@ -1971,6 +2175,7 @@ CtrlObject->Plugins.CurViewer=this; //HostFileViewer; } + enum SEARCHDLG { SD_DOUBLEBOX, @@ -1991,9 +2196,18 @@ enum { - DM_SDSETVISIBILITY = DM_USER+1, + DM_SDSETVISIBILITY = DM_USER + 1, + DM_SDREXVISIBILITY = DM_USER + 2 }; +struct MyDialogData +{ + Viewer *viewer; + bool edit_autofocus; + bool hex_mode; + bool recursive; +}; + INT_PTR WINAPI ViewerSearchDlgProc(HANDLE hDlg,int Msg,int Param1,void* Param2) { switch (Msg) @@ -2010,42 +2224,133 @@ SendDlgMessage(hDlg,DM_SHOWITEM,SD_EDIT_TEXT,ToPtr(!Param1)); SendDlgMessage(hDlg,DM_SHOWITEM,SD_EDIT_HEX,ToPtr(Param1)); SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_CASE,ToPtr(!Param1)); - SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_WORDS,ToPtr(!Param1)); - //SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_REGEXP,!Param1); + int re = SendDlgMessage(hDlg, DM_GETCHECK,SD_CHECKBOX_REGEXP,0) == BSTATE_CHECKED; + int ww = !Param1 && !re; + SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_WORDS,ToPtr(ww)); + SendDlgMessage(hDlg,DM_ENABLE,SD_CHECKBOX_REGEXP,ToPtr(!Param1)); + SendDlgMessage(hDlg, DM_SDREXVISIBILITY, re && !Param1, 0); return TRUE; } + case DM_SDREXVISIBILITY: + { + int show = 1; + if ( Param1 ) + { + int tlen = (int)SendDlgMessage(hDlg, DM_GETTEXTPTR, SD_EDIT_TEXT, 0); + show = 0; + if ( tlen > 0 ) + { + RegExp re; + wchar_t t[128], *tmp = t; + if (tlen > (int)ARRAYSIZE(t)) + tmp = new wchar_t[tlen]; + SendDlgMessage(hDlg, DM_GETTEXTPTR, SD_EDIT_TEXT, tmp); + string sre = tmp; + InsertRegexpQuote(sre); + show = re.Compile(sre.CPtr(), OP_PERLSTYLE); + if (tmp != t) + delete[] tmp;; + } + } + SendDlgMessage(hDlg, DM_ENABLE, SD_TEXT_SEARCH, ToPtr(show)); + SendDlgMessage(hDlg, DM_ENABLE, SD_BUTTON_OK, ToPtr(show)); + return TRUE; + } + case DN_KILLFOCUS: + { + if ( SD_EDIT_TEXT == Param1 || SD_EDIT_HEX == Param1 ) + { + MyDialogData *my = (MyDialogData *)SendDlgMessage(hDlg, DM_GETITEMDATA, SD_EDIT_TEXT, 0); + my->hex_mode = (SD_EDIT_HEX == Param1); + } + break; + } case DN_BTNCLICK: { + bool need_focus = false; + MyDialogData *my = (MyDialogData *)SendDlgMessage(hDlg, DM_GETITEMDATA, SD_EDIT_TEXT, 0); + int cradio = (my->hex_mode ? SD_RADIO_HEX : SD_RADIO_TEXT); + if ((Param1 == SD_RADIO_TEXT || Param1 == SD_RADIO_HEX) && Param2) { - SendDlgMessage(hDlg, DM_ENABLEREDRAW, FALSE, 0); - Viewer *viewer = (Viewer *)SendDlgMessage(hDlg, DM_GETITEMDATA, SD_EDIT_TEXT, 0); + need_focus = true; + if ( Param1 != cradio) + { + bool new_hex = (Param1 == SD_RADIO_HEX); - int sd_dst = Param1 == SD_RADIO_HEX ? SD_EDIT_HEX : SD_EDIT_TEXT; - int sd_src = Param1 == SD_RADIO_TEXT ? SD_EDIT_HEX : SD_EDIT_TEXT; + SendDlgMessage(hDlg, DM_ENABLEREDRAW, FALSE, 0); - const wchar_t *ps = (const wchar_t *)SendDlgMessage(hDlg, DM_GETCONSTTEXTPTR, sd_src, 0); - string strTo; - viewer->SearchTextTransform(strTo, ps, Param1 == SD_RADIO_TEXT); + int sd_dst = new_hex ? SD_EDIT_HEX : SD_EDIT_TEXT; + int sd_src = new_hex ? SD_EDIT_TEXT : SD_EDIT_HEX; - SendDlgMessage(hDlg, DM_SETTEXTPTR, sd_dst, const_cast<wchar_t*>(strTo.CPtr())); - SendDlgMessage(hDlg, DM_SDSETVISIBILITY, Param1 == SD_RADIO_HEX, 0); + EditorSetPosition esp; + esp.CurPos = -1; + SendDlgMessage(hDlg, DM_GETEDITPOSITION, sd_src, &esp); + const wchar_t *ps = (const wchar_t *)SendDlgMessage(hDlg, DM_GETCONSTTEXTPTR, sd_src, 0); + string strTo; + my->viewer->SearchTextTransform(strTo, ps, !new_hex, esp.CurPos); - if (!strTo.IsEmpty()) - { - int changed = (int)SendDlgMessage(hDlg, DM_EDITUNCHANGEDFLAG, sd_src, ToPtr(-1)); - SendDlgMessage(hDlg, DM_EDITUNCHANGEDFLAG, sd_dst, ToPtr(changed)); + SendDlgMessage(hDlg, DM_SETTEXTPTR, sd_dst, ToPtr((INT_PTR)strTo.CPtr())); + SendDlgMessage(hDlg, DM_SDSETVISIBILITY, new_hex, 0); + if (esp.CurPos >= 0) + { + int p = esp.CurPos; + if (SendDlgMessage(hDlg, DM_GETEDITPOSITION, sd_dst, &esp)) + { + esp.CurPos = esp.CurTabPos = p; + esp.LeftPos = 0; + SendDlgMessage(hDlg, DM_SETEDITPOSITION, sd_dst, &esp); + } + } + + if (!strTo.IsEmpty()) + { + int changed = (int)SendDlgMessage(hDlg, DM_EDITUNCHANGEDFLAG, sd_src, ToPtr(-1)); + SendDlgMessage(hDlg, DM_EDITUNCHANGEDFLAG, sd_dst, ToPtr(changed)); + } + + SendDlgMessage(hDlg,DM_ENABLEREDRAW,TRUE,0); + my->hex_mode = new_hex; + if ( !my->edit_autofocus ) + return TRUE; } + } + else if ( Param1 == SD_CHECKBOX_REGEXP ) + { + SendDlgMessage(hDlg, DM_SDSETVISIBILITY, my->hex_mode, 0); + } - SendDlgMessage(hDlg,DM_ENABLEREDRAW,TRUE,0); + if ( my->edit_autofocus && !my->recursive ) + { + if ( need_focus + || Param1 == SD_CHECKBOX_CASE + || Param1 == SD_CHECKBOX_WORDS + || Param1 == SD_CHECKBOX_REVERSE + || Param1 == SD_CHECKBOX_REGEXP + ){ + my->recursive = true; + SendDlgMessage(hDlg, DM_SETFOCUS, my->hex_mode ? SD_EDIT_HEX : SD_EDIT_TEXT, 0); + my->recursive = false; + } + } + + if (need_focus) return TRUE; - } + else + break; } + case DN_EDITCHANGE: + { + if ( Param1 == SD_EDIT_TEXT && SendDlgMessage(hDlg,DM_GETCHECK,SD_CHECKBOX_REGEXP,0) == BSTATE_CHECKED ) + SendDlgMessage(hDlg, DM_SDREXVISIBILITY, 1, 0); + break; + } 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); + MyDialogData *my = (MyDialogData *)SendDlgMessage(hDlg, DM_GETITEMDATA, SD_EDIT_TEXT, 0); + SendDlgMessage(hDlg, DM_SETFOCUS, (my->hex_mode ? SD_EDIT_HEX : SD_EDIT_TEXT), 0); return FALSE; } } @@ -2059,10 +2364,13 @@ static void PR_ViewerSearchMsg() { PreRedrawItem preRedrawItem=PreRedraw.Peek(); - ViewerSearchMsg((const wchar_t*)preRedrawItem.Param.Param1,(int)(INT_PTR)preRedrawItem.Param.Param2); + const wchar_t *name = (const wchar_t*)preRedrawItem.Param.Param1; + int percent = (int)(INT_PTR)preRedrawItem.Param.Param2; + int search_hex = (int)(INT_PTR)preRedrawItem.Param.Param3; + ViewerSearchMsg(name, percent, search_hex); } -void ViewerSearchMsg(const wchar_t *MsgStr,int Percent) +void ViewerSearchMsg(const wchar_t *MsgStr, int Percent, int SearchHex) { string strProgress; @@ -2093,6 +2401,7 @@ PreRedrawItem preRedrawItem=PreRedraw.Peek(); preRedrawItem.Param.Param1=(void*)MsgStr; preRedrawItem.Param.Param2=(LPVOID)(INT_PTR)Percent; + preRedrawItem.Param.Param3=(LPVOID)(INT_PTR)SearchHex; PreRedraw.SetParam(preRedrawItem.Param); } @@ -2109,15 +2418,17 @@ } } -static int hex2ss(const wchar_t *from, char *c1, int mb) +static int hex2ss(const wchar_t *from, char *c1, int mb, int *pos = 0) { - int nb, i, v, sub = 0; + int nb, i, v, sub = 0, ps = 0, p0 = (pos ? *pos : -1), p1 = -1; wchar_t ch; nb = i = v = 0; for (;;) { ch = *from++; + ++ps; + if (ch >= L'0' && ch <= L'9') sub = L'0'; else if (ch >= L'A' && ch <= L'F') sub = L'A' - 10; else if (ch >= L'a' && ch <= L'f') sub = L'a' - 10; @@ -2125,6 +2436,8 @@ { if (i > 0) { + if ( p0 >= 0 && ps > p0 && p1 < 0 ) + p1 = nb; c1[nb++] = (char)v; i = 0; } @@ -2136,6 +2449,8 @@ v = v*16 + ((int)ch - sub); if (++i >= 2) { + if ( p0 >= 0 && ps > p0 && p1 < 0 ) + p1 = nb; c1[nb++] = (char)v; i = 0; if (nb >= mb) @@ -2145,10 +2460,12 @@ #ifdef _DEBUG if (nb < mb) c1[nb] = '\0'; #endif + if ( p1 >= 0 && pos ) + *pos = p1; return nb; } -void Viewer::SearchTextTransform( UnicodeString &to, const wchar_t *from, bool hex2text ) +void Viewer::SearchTextTransform( UnicodeString &to, const wchar_t *from, bool hex2text, int &pos ) { int nb, i, v; char c1[128]; @@ -2156,7 +2473,7 @@ if (hex2text) { - nb = hex2ss(from, c1, ARRAYSIZE(c1)); + nb = hex2ss(from, c1, ARRAYSIZE(c1), &pos); if (IsUnicodeCodePage(VM.CodePage)) { @@ -2171,10 +2488,16 @@ ch = 0xffff; // encode L'\0' to += ch; } + if ( pos >= 0 ) + pos /= 2; } else { int nw = MultiByteToWideChar(VM.CodePage,0, c1,nb, ss,ARRAYSIZE(ss)); + if ( pos >= 0 ) + { + pos = MultiByteToWideChar(VM.CodePage,0, c1,pos, NULL,0); + } for (i=0; i < nw; ++i) if (!ss[i]) ss[i] = 0xffff; @@ -2184,8 +2507,12 @@ } else // text2hex { + int ps = 0, pd = 0, p0 = pos, p1 = -1; while (*from) { + if ( ps == p0 ) + p1 = pd; + ++ps; ch = *from++; if (0xffff == ch) // 0xffff - invalid unicode char ch = 0x0000; // it used to transfer '\0' in zero terminated string @@ -2199,398 +2526,737 @@ nb = 2; c1[0] = (char)HIBYTE(ch); c1[1] = (char)LOBYTE(ch); break; default: - nb = WideCharToMultiByte(VM.CodePage,0, &ch, 1, c1, 4, nullptr, nullptr); + nb = WideCharToMultiByte(VM.CodePage,0, &ch,1, c1,4, NULL,NULL); break; } ss2hex(to, c1, nb, L'\0'); + pd += nb * 3; } + pos = p1; } } -/* $ 27.01.2003 VVM - + �������� Next ����� �������� ������: - 0 - ���� ����� - 1 - ��������� ����� �� ������� ������ - 2 - ��������� ����� � ����� ����� -*/ +struct Viewer::search_data +{ + INT64 CurPos; + INT64 MatchPos; + const char *search_bytes; + const wchar_t *search_text; + int search_len; + int ch_size; + bool is_utf8; + bool first_Rex; + RegExp *pRex; -void Viewer::Search(int Next,int FirstChar) -{ - const wchar_t *TextHistoryName=L"SearchText"; - const wchar_t *HexMask=L"HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH "; - FarDialogItem SearchDlgData[]= + search_data() { - {DI_DOUBLEBOX,3,1,72,11,0,nullptr,nullptr,0,MSG(MViewSearchTitle)}, - {DI_TEXT,5,2,0,2,0,nullptr,nullptr,0,MSG(MViewSearchFor)}, - {DI_EDIT,5,3,70,3,0,TextHistoryName,nullptr,DIF_FOCUS|DIF_HISTORY|DIF_USELASTHISTORY,L""}, - {DI_FIXEDIT,5,3,70,3,0,nullptr,HexMask,DIF_MASKEDIT,L""}, - {DI_TEXT,3,4,0,4,0,nullptr,nullptr,DIF_SEPARATOR,L""}, - {DI_RADIOBUTTON,5,5,0,5,1,nullptr,nullptr,DIF_GROUP,MSG(MViewSearchForText)}, - {DI_RADIOBUTTON,5,6,0,6,0,nullptr,nullptr,0,MSG(MViewSearchForHex)}, - {DI_CHECKBOX,40,5,0,5,0,nullptr,nullptr,0,MSG(MViewSearchCase)}, - {DI_CHECKBOX,40,6,0,6,0,nullptr,nullptr,0,MSG(MViewSearchWholeWords)}, - {DI_CHECKBOX,40,7,0,7,0,nullptr,nullptr,0,MSG(MViewSearchReverse)}, - {DI_CHECKBOX,40,8,0,8,0,nullptr,nullptr,DIF_DISABLE,MSG(MViewSearchRegexp)}, - {DI_TEXT,3,9,0,9,0,nullptr,nullptr,DIF_SEPARATOR,L""}, - {DI_BUTTON,0,10,0,10,0,nullptr,nullptr,DIF_DEFAULTBUTTON|DIF_CENTERGROUP,MSG(MViewSearchSearch)}, - {DI_BUTTON,0,10,0,10,0,nullptr,nullptr,DIF_CENTERGROUP,MSG(MViewSearchCancel)}, - }; - MakeDialogItemsEx(SearchDlgData,SearchDlg); - string strSearchStr; - char search_bytes[128]; - string strMsgStr; - __int64 MatchPos=0; - int SearchLength,Case,WholeWords,ReverseSearch,Match,SearchRegexp; + CurPos = MatchPos = -1; + search_bytes = nullptr; + search_text = nullptr; + search_len = ch_size = 0; + is_utf8 = false; + first_Rex = true; + pRex = nullptr; + } - if (!ViewFile.Opened() || (Next && strLastSearchStr.IsEmpty())) - return; + ~search_data() + { + delete pRex; + } +}; - if (!strLastSearchStr.IsEmpty()) - strSearchStr = strLastSearchStr; +int Viewer::search_hex_forward( search_data* sd ) +{ + char *buff = (char *)Search_buffer; + const char *search_str = sd->search_bytes; + int bsize = Search_buffer_size * static_cast<int>(sizeof(wchar_t)), slen = sd->search_len; + INT64 to, cpos = sd->CurPos; + + bool up_half = cpos >= StartSearchPos; + if ( up_half ) + { + if ( (to = FileSize) - cpos <= bsize ) + SetFileSize(); + to = FileSize; + } else - strSearchStr.Clear(); + { + to = StartSearchPos + slen - 1; + if ( to > FileSize ) + to = FileSize; + } - SearchDlg[SD_RADIO_TEXT].Selected=!LastSearchHex; - SearchDlg[SD_RADIO_HEX].Selected=LastSearchHex; - SearchDlg[SD_CHECKBOX_CASE].Selected=LastSearchCase; - SearchDlg[SD_CHECKBOX_WORDS].Selected=LastSearchWholeWords; - SearchDlg[SD_CHECKBOX_REVERSE].Selected=LastSearchReverse; - SearchDlg[SD_CHECKBOX_REGEXP].Selected=LastSearchRegexp; + int nb = (to - cpos < bsize ? static_cast<int>(to - cpos) : bsize); + vseek(cpos, SEEK_SET); + DWORD nr = 0; + Reader.Read(buff, static_cast<DWORD>(nb), &nr); + int n1 = static_cast<int>(nr); + if ( n1 != nb ) + SetFileSize(); - if (SearchFlags.Check(REVERSE_SEARCH)) - SearchDlg[SD_CHECKBOX_REVERSE].Selected=!SearchDlg[SD_CHECKBOX_REVERSE].Selected; + if ( n1 < slen ) + { + if ( !up_half || StartSearchPos <= 0 ) + return -1; + sd->CurPos = 0; + return 0; + } - if (SearchDlg[SD_RADIO_HEX].Selected) + char *ps = buff; + while ( nullptr != (ps = static_cast<char *>(memchr(ps, search_str[0], n1-slen+1))) ) { - int nb = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); - strSearchStr.Clear(); - ss2hex(strSearchStr, search_bytes, nb, L'\0'); - SearchDlg[SD_EDIT_HEX].strData = strSearchStr; + if ( slen <= 1 || 0 == memcmp(ps+1, search_str+1, slen-1) ) + { + sd->MatchPos = cpos + static_cast<INT64>(ps - buff); + return +1; // found + } + ++ps; + n1 = static_cast<int>(nr - (ps - buff)); } + + sd->CurPos = cpos + nr - slen + 1; + return (up_half || sd->CurPos < StartSearchPos ? 0 : -1); +} + +int Viewer::search_hex_backward( search_data* sd ) +{ + char *buff = (char *)Search_buffer; + const char *search_str = sd->search_bytes; + int bsize = Search_buffer_size * static_cast<int>(sizeof(wchar_t)), slen = sd->search_len; + INT64 to, cpos = sd->CurPos; + + bool lo_half = cpos <= StartSearchPos; + if ( lo_half ) + { + to = 0; + } else - SearchDlg[SD_EDIT_TEXT].strData = strSearchStr; + { + to = StartSearchPos - slen + 1; + if ( to < 0 ) + to = 0; + } - SearchDlg[SD_EDIT_TEXT].UserData = this; + int nb = (cpos - to < bsize ? static_cast<int>(cpos - to) : bsize); + vseek(cpos-nb, SEEK_SET); + DWORD nr = 0; + Reader.Read(buff, static_cast<DWORD>(nb), &nr); + int n1 = static_cast<int>(nr); + if ( n1 != nb ) + { + SetFileSize(); + cpos = vtell(); + } - if (!Next) + if ( n1 < slen ) { - SearchFlags.Flags = 0; - Dialog Dlg(SearchDlg,ARRAYSIZE(SearchDlg),ViewerSearchDlgProc); - Dlg.SetPosition(-1,-1,76,13); - Dlg.SetHelp(L"ViewerSearch"); + if ( !lo_half ) + return -1; + SetFileSize(); + if ( StartSearchPos >= FileSize ) + return -1; + sd->CurPos = FileSize; + return 0; + } - if (FirstChar) + for ( char *ps = buff + n1 - 1; ps >= buff + slen - 1; --ps ) + { + if ( *ps == search_str[slen-1] ) { - Dlg.InitDialog(); - Dlg.Show(); - Dlg.ProcessKey(FirstChar); + if ( slen <= 1 || 0 == memcmp(ps-slen+1, search_str, slen-1) ) + { + sd->MatchPos = static_cast<INT64>(cpos-n1+(ps-slen+1-buff)); + return +1; + } } + } - Dlg.Process(); + sd->CurPos = cpos - nr + slen - 1; + return (lo_half || sd->CurPos > StartSearchPos ? 0 : -1); +} - if (Dlg.GetExitCode()!=SD_BUTTON_OK) - return; +int Viewer::search_text_forward( search_data* sd ) +{ + int bsize = 8192, slen = sd->search_len, ww = (LastSearchWholeWords ? 1 : 0); + wchar_t prev_char = L'\0', *buff = Search_buffer, *t_buff = (sd->is_utf8 ? buff + bsize : nullptr); + const wchar_t *search_str = sd->search_text; + INT64 to1, to, cpos = sd->CurPos; + + vseek(cpos, SEEK_SET); + if ( ww ) + prev_char = vgetc_prev(); + + bool up_half = cpos >= StartSearchPos; + if ( up_half ) + { + if ( (to = FileSize) - cpos <= bsize ) + SetFileSize(); + to = FileSize; } + else + { + to = StartSearchPos; + if ( to > FileSize ) + to = FileSize; + } - SearchHex=SearchDlg[SD_RADIO_HEX].Selected; - Case=SearchDlg[SD_CHECKBOX_CASE].Selected; - WholeWords=SearchDlg[SD_CHECKBOX_WORDS].Selected; - ReverseSearch=SearchDlg[SD_CHECKBOX_REVERSE].Selected; - SearchRegexp=SearchDlg[SD_CHECKBOX_REGEXP].Selected; + int nb = (to - cpos > bsize ? bsize : static_cast<int>(to - cpos)); + int nw = vread(buff, nb, t_buff); + to1 = vtell(); + if ( !up_half && nb + 3*(slen+ww) < bsize && !veof() ) + { + int nw1 = vread(buff+nw, 3*(slen+ww), t_buff ? t_buff+nw : nullptr); + nw1 = (nw1 > slen+ww-1 ? slen+ww-1 : nw1); + nw += nw1; + to1 = to + (t_buff ? GetStrBytesNum(t_buff, nw1) : sd->ch_size * nw1); + } - bool t_utf8 = !SearchHex && VM.CodePage == CP_UTF8; + int is_eof = (to1 >= FileSize ? 1 : 0), iLast = nw - slen - ww + is_eof; + if ( !LastSearchCase ) + CharUpperBuff(buff, nw); - if (SearchHex) + for ( int i = 0; i <= iLast; ++i ) { - strSearchStr = SearchDlg[SD_EDIT_HEX].strData; - SearchLength = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); - strSearchStr.Clear(); - ss2hex(strSearchStr, search_bytes, SearchLength, L' '); + if ( ww ) + { + if ( !is_word_div(i > 0 ? buff[i-1] : prev_char)) + continue; + if ( !(i == iLast && is_eof) && !is_word_div(buff[i+slen]) ) + continue; + } + if ( buff[i] != search_str[0] + || (slen > 1 && buff[i+1] != search_str[1]) + || (slen > 2 && 0 != wmemcmp(buff+i+2, search_str+2, slen-2)) + ) continue; + + sd->MatchPos = cpos + GetStrBytesNum(t_buff, i); + sd->search_len = GetStrBytesNum(t_buff+i, slen); + return +1; } + + if ( up_half && is_eof ) + { + sd->CurPos = 0; + return (StartSearchPos > 0 ? 0 : -1); + } else { - strSearchStr = SearchDlg[SD_EDIT_TEXT].strData; - SearchLength = (int)strSearchStr.GetLength(); - size_t pos = 0; - while (strSearchStr.Pos(pos, 0xffff)) - strSearchStr.Replace(pos, 1, L'\0'); + if ( iLast < 0 || (!up_half && to1 > StartSearchPos) ) + return -1; + sd->CurPos = to1; + return 0; } +} - strLastSearchStr = strSearchStr; - LastSearchHex=SearchHex; - LastSearchCase=Case; - LastSearchWholeWords=WholeWords; +int Viewer::search_text_backward( search_data* sd ) +{ + int bsize = 8192, slen = sd->search_len, ww = (LastSearchWholeWords ? 1 : 0); + wchar_t *buff = Search_buffer, *t_buff = (sd->is_utf8 ? buff + bsize : nullptr); + const wchar_t *search_str = sd->search_text; + INT64 to1, to, cpos = sd->CurPos; - if (!SearchFlags.Check(REVERSE_SEARCH)) - LastSearchReverse=ReverseSearch; + bool up_half = cpos > StartSearchPos; + to = (up_half ? StartSearchPos : 0); - LastSearchRegexp=SearchRegexp; + int nb = (cpos - to > bsize ? bsize : static_cast<int>(cpos- to)); + if ( up_half && nb + 3*(slen+ww) < bsize && cpos > nb ) + { + if ( sd->ch_size > 0 ) + { + nb += sd->ch_size * (slen + ww - 1); + if (cpos < nb) + nb = static_cast<int>(cpos); + } + else + { + to1 = cpos - nb - 3*(slen + ww - 1); + if (to1 < 0) + to1 = 0; + int nb1 = static_cast<int>(cpos - nb - to1); + vseek(to1, SEEK_SET); + int nw1 = vread(buff, nb1, t_buff); + if ( nw1 > slen + ww - 1 ) + nb1 = GetStrBytesNum(t_buff + nw1 - (slen + ww - 1), slen + ww - 1); + nb += nb1; + } + } - if (!SearchLength) - return; + cpos -= nb; + vseek(cpos, SEEK_SET); + int nw = vread(buff, nb, t_buff); + if ( !LastSearchCase ) + CharUpperBuff(buff, nw); + int is_eof = (veof() ? 1 : 0), iFirst = ww * (cpos > 0 ? 1 : 0), iLast = nw - slen - ww + ww*is_eof; + for ( int i = iLast; i >= iFirst; --i ) { - TPreRedrawFuncGuard preRedrawFuncGuard(PR_ViewerSearchMsg); - //SaveScreen SaveScr; - SetCursorType(FALSE,0); - strMsgStr = strSearchStr; + if ( ww ) + { + if ( i > 0 && !is_word_div(buff[i-1]) ) + continue; + if ( !(i == iLast && is_eof) && !is_word_div(buff[i+slen]) ) + continue; + } + if ( buff[i] != search_str[0] + || (slen > 1 && buff[i+1] != search_str[1]) + || (slen > 2 && 0 != wmemcmp(buff+i+2, search_str+2, slen-2)) + ) continue; - if (strMsgStr.GetLength()+18 > static_cast<DWORD>(ObjWidth)) - TruncStrFromEnd(strMsgStr, ObjWidth-18); + sd->MatchPos = cpos + GetStrBytesNum(t_buff, i); + sd->search_len = GetStrBytesNum(t_buff+i, slen); + return +1; + } - if (!SearchHex) - InsertQuote(strMsgStr); + int ret = 0; + if ( up_half ) + ret = (cpos <= StartSearchPos ? -1 : 0); + else + { + if ( cpos <= 0 ) + { + SetFileSize(); + cpos = FileSize; + ret = (StartSearchPos >= FileSize ? -1 : 0); + } + } + sd->CurPos = cpos; + return ret; +} - if (SearchHex) - Case = 1 + (WholeWords = 0); +int Viewer::read_line(wchar_t *buf, wchar_t *tbuf, INT64 cpos, int adjust, INT64 &lpos, int &lsize) +{ + int llen = 0; - if (!Case && !SearchHex) - strSearchStr.Upper(); + INT64 save_FilePos = FilePos, save_LastPage = LastPage; + int save_Hex = VM.Hex, save_Wrap = VM.Wrap, save_WordWrap = VM.WordWrap; + VM.Hex = VM.Wrap = VM.WordWrap = 0; - SelectSize = 0; + FilePos = cpos; + if ( adjust ) + { + if ( adjust > 0 ) + AdjustFilePos(); + else + Up(1); + } - if (Next) + vseek(lpos = vString.nFilePos = FilePos, SEEK_SET); + vString.linesize = 0; + ReadString(&vString, -1, false); // read unwrapped text line + + vseek(FilePos, SEEK_SET); + llen = vread(buf, lsize = vString.linesize, tbuf); + if ( llen > 0 && vString.have_eol ) // remove eol-s + { + --llen; + if ( llen > 0 && (buf[llen-1] == L'\r' || buf[llen-1] == L'\n') ) + --llen; + } + buf[llen >= 0 ? llen : 0] = L'\0'; + + VM.Hex = save_Hex; VM.Wrap = save_Wrap; VM.WordWrap = save_WordWrap; + FilePos = save_FilePos; LastPage = save_LastPage; + return llen; +} + +int Viewer::search_regex_forward( search_data* sd ) +{ + assert(sd->pRex); + assert(Search_buffer_size >= 2*MAX_VIEWLINEB); + + wchar_t *line = Search_buffer, *t_line = sd->is_utf8 ? Search_buffer + MAX_VIEWLINEB : nullptr; + INT64 cpos = sd->CurPos, bpos = 0; + + int first = (sd->first_Rex ? +1 : 0); + sd->first_Rex = false; + bool up_half = cpos >= StartSearchPos; + + int lsize = 0, nw = read_line(line, t_line, cpos, first, bpos, lsize); + if ( lsize <= 0 ) + { + sd->CurPos = 0; + return (up_half && StartSearchPos > 0 ? 0 : -1); + } + + int off = 0; + for (;;) + { + if ( off > nw ) + break; + + SMatch m[1]; + int n = static_cast<int>(ARRAYSIZE(m)); + if ( !sd->pRex->SearchEx(line, line+off, line+nw, m, n) ) // doesn't match + break; + + INT64 fpos = bpos + GetStrBytesNum(t_line, m[0].start); + if ( fpos < cpos ) { - if (Next == 2) - { - SearchFlags.Set(SEARCH_MODE2); - LastSelPos = ReverseSearch?FileSize:0; - } - else - { - LastSelPos = SelectPos + (ReverseSearch?-1:1); - } + off = m[0].start + 1; // skip + continue; } - else + else if ( !up_half && fpos >= StartSearchPos ) { - LastSelPos = FilePos; + break; // done - not found + } + else // found + { + sd->MatchPos = fpos; + sd->search_len = GetStrBytesNum(t_line+off, m[0].end - m[0].start); + return +1; + } + } - if (!LastSelPos || LastSelPos == FileSize) - SearchFlags.Set(SEARCH_MODE2); + sd->CurPos = vtell(); + if ( up_half ) + { + if ( veof() ) + { + sd->CurPos = 0; + return (StartSearchPos > 0 ? 0 : -1); } + return 0; + } + else + { + return (sd->CurPos >= StartSearchPos ? -1 : 0); + } +} - vseek(LastSelPos,SEEK_SET); - Match = 0; +int Viewer::search_regex_backward( search_data* sd ) +{ + assert(sd->pRex); + assert(Search_buffer_size >= 2*MAX_VIEWLINEB); - if (SearchLength > 0 && (!ReverseSearch || LastSelPos > 0)) + wchar_t *line = Search_buffer, *t_line = sd->is_utf8 ? Search_buffer + MAX_VIEWLINEB : nullptr; + INT64 cpos = sd->CurPos, bpos = 0, prev_pos = -1; + + bool up_half = cpos > StartSearchPos; + + int off=0, lsize=0, nw, prev_len = -1, flen; + nw = read_line(line, t_line, cpos, -1, bpos, lsize); + for (;;) + { + if ( lsize <= 0 || off > nw ) + break; + + SMatch m[1]; + int n = static_cast<int>(ARRAYSIZE(m)); + if ( !sd->pRex->SearchEx(line, line+off, line+nw, m, n) ) + break; + + INT64 fpos = bpos + GetStrBytesNum(t_line, m[0].start); + flen = GetStrBytesNum(t_line + m[0].start, m[0].end - m[0].start); + if ( fpos+flen > cpos ) + break; + + if ( !(up_half && fpos+flen <= StartSearchPos) ) { - wchar_t *Buf = new wchar_t[8192 + 8192], *t_Buf = t_utf8 ? Buf + 8192 : nullptr; - int buf_size = 8192, seek_size = 1; - char *byte_buff = nullptr; - if (SearchHex) - { - byte_buff = (char *)Buf; - buf_size *= 2*(int)sizeof(wchar_t); - seek_size = IsUnicodeCodePage(VM.CodePage) ? 2 : 1; - } + prev_pos = fpos; + prev_len = flen; + } - __int64 CurPos=LastSelPos; - int BufSize = buf_size; + off = m[0].start + 1; // skip + continue; + } - if (ReverseSearch) - { - /* $ 01.08.2000 KM - ������� �������� CurPos � ���� Whole words - */ - if (WholeWords) - CurPos -= BufSize/seek_size - SearchLength/seek_size + 1; - else - CurPos -= BufSize/seek_size - SearchLength/seek_size; + if ( prev_len >= 0 ) + { + sd->MatchPos = prev_pos; + sd->search_len = prev_len; + return +1; + } + + if ( (sd->CurPos = bpos) <= 0 ) + { + SetFileSize(); + sd->CurPos = FileSize; + return (StartSearchPos >= FileSize ? -1 : 0); + } + return (up_half && bpos <= StartSearchPos ? -1 : 0); +} - if (CurPos<0) - BufSize += (int)CurPos * seek_size; - } - int ReadSize; - TaskBar TB; - wakeful W; - INT64 StartPos = vtell(); - DWORD StartTime = GetTickCount(); +/* + + �������� Next ����� �������� ������: + 0 - ���� ����� + 1 - ��������� ����� �� ������� ������ +-1 - ��������� ����� �� ������� ������ � ��������������� ����������� + 2 - ��������� ����� � �����/���� ����� +*/ +void Viewer::Search(int Next,int FirstChar) +{ + if (!ViewFile.Opened() || (Next && strLastSearchStr.IsEmpty())) + return; - while (!Match) - { - /* $ 01.08.2000 KM - �������� ������ if (ReverseSearch && CurPos<0) �� if (CurPos<0), - ��� ��� ��� ����� ����� � LastSelPos=0xFFFFFFFF, ����� - ���������� ��� � �� ������. - */ - if (CurPos < 0) - CurPos = 0; + string strSearchStr, strMsgStr; + char search_bytes[128]; + int Case,WholeWords,ReverseSearch,SearchRegexp,SearchHex; - vseek(CurPos, SEEK_SET); + SearchHex = LastSearchHex; + Case = LastSearchCase; + WholeWords = LastSearchWholeWords; + ReverseSearch = LastSearchReverse; + SearchRegexp = LastSearchRegexp; + strSearchStr.Clear(); + if (!strLastSearchStr.IsEmpty()) + strSearchStr = strLastSearchStr; - if (SearchHex) - { - DWORD nr = 0; - Reader.Read(byte_buff, (DWORD)BufSize, &nr); - ReadSize = (int)nr; - } - else - { - ReadSize = vread(Buf, BufSize, t_Buf); - } - if (ReadSize <= 0) - break; + search_data sd; + int (Viewer::* searcher)( Viewer::search_data *p_sd ) = nullptr; - DWORD CurTime=GetTickCount(); + if ( !Next ) + { + const wchar_t *TextHistoryName=L"SearchText"; + const wchar_t *HexMask = L"HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH HH " ; + FarDialogItem SearchDlgData[]= + { + {DI_DOUBLEBOX,3,1,72,11,0,nullptr,nullptr,0,MSG(MViewSearchTitle)}, + {DI_TEXT,5,2,0,2,0,nullptr,nullptr,0,MSG(MViewSearchFor)}, + {DI_EDIT,5,3,70,3,0,TextHistoryName,nullptr,DIF_FOCUS|DIF_HISTORY|DIF_USELASTHISTORY,L""}, + {DI_FIXEDIT,5,3,70,3,0,nullptr,HexMask,DIF_MASKEDIT,L""}, + {DI_TEXT,3,4,0,4,0,nullptr,nullptr,DIF_SEPARATOR,L""}, + {DI_RADIOBUTTON,5,5,0,5,1,nullptr,nullptr,DIF_GROUP,MSG(MViewSearchForText)}, + {DI_RADIOBUTTON,5,6,0,6,0,nullptr,nullptr,0,MSG(MViewSearchForHex)}, + {DI_CHECKBOX,40,5,0,5,0,nullptr,nullptr,0,MSG(MViewSearchCase)}, + {DI_CHECKBOX,40,6,0,6,0,nullptr,nullptr,0,MSG(MViewSearchWholeWords)}, + {DI_CHECKBOX,40,7,0,7,0,nullptr,nullptr,0,MSG(MViewSearchReverse)}, + {DI_CHECKBOX,40,8,0,8,0,nullptr,nullptr,DIF_DISABLE,MSG(MViewSearchRegexp)}, + {DI_TEXT,3,9,0,9,0,nullptr,nullptr,DIF_SEPARATOR,L""}, + {DI_BUTTON,0,10,0,10,0,nullptr,nullptr,DIF_DEFAULTBUTTON|DIF_CENTERGROUP,MSG(MViewSearchSearch)}, + {DI_BUTTON,0,10,0,10,0,nullptr,nullptr,DIF_CENTERGROUP,MSG(MViewSearchCancel)}, + }; + MakeDialogItemsEx(SearchDlgData,SearchDlg); - if (CurTime-StartTime>RedrawTimeout) - { - StartTime=CurTime; + SearchDlg[SD_RADIO_TEXT].Selected=!LastSearchHex; + SearchDlg[SD_RADIO_HEX].Selected=LastSearchHex; + SearchDlg[SD_CHECKBOX_CASE].Selected=LastSearchCase; + SearchDlg[SD_CHECKBOX_WORDS].Selected=LastSearchWholeWords; + SearchDlg[SD_CHECKBOX_REVERSE].Selected=LastSearchReverse; + SearchDlg[SD_CHECKBOX_REGEXP].Selected=LastSearchRegexp; - if (CheckForEscSilent()) - { - if (ConfirmAbortOp()) - { - Redraw(); - return; - } - } + if (SearchDlg[SD_RADIO_HEX].Selected) + { + int nb = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); + strSearchStr.Clear(); + ss2hex(strSearchStr, search_bytes, nb, L'\0'); + SearchDlg[SD_EDIT_HEX].strData = strSearchStr; + } + else + SearchDlg[SD_EDIT_TEXT].strData = strSearchStr; - INT64 Total=ReverseSearch?StartPos:FileSize-StartPos; - INT64 Current=_abs64(CurPos-StartPos); - int Percent=Total>0?static_cast<int>(Current*100/Total):-1; - // � ����� ���� ���� ����������� �������, �� ��������� - // �������� ����� �� ���� 100. ����������� ��� ������. - if (Percent>100) - { - SetFileSize(); - Total=FileSize-StartPos; - Percent=Total>0?static_cast<int>(Current*100/Total):-1; - if (Percent>100) - { - Percent=100; - } - } - ViewerSearchMsg(strMsgStr,Percent); - } + MyDialogData my; + // + my.viewer = this; + my.edit_autofocus = (ViOpt.SearchEditFocus != 0); + my.hex_mode = (LastSearchHex != 0); + my.recursive = false; + // + SearchDlg[SD_EDIT_TEXT].UserData = &my; - /* $ 01.08.2000 KM - ������� ����� �������� �� Case sensitive � Hex - � ���� ���, ����� Buf ��������� � ������� �������� - */ - if (!Case && !SearchHex) - CharUpperBuff(Buf, ReadSize); + Dialog Dlg(SearchDlg,ARRAYSIZE(SearchDlg),ViewerSearchDlgProc); + Dlg.SetPosition(-1,-1,76,13); + Dlg.SetHelp(L"ViewerSearch"); - /* $ 01.08.2000 KM - ����� ����� ������ ����� ��������� ��������� ������ - � Buf � ������� ��������, ���� ����� �� ���������������� - ��� �� ���� Hex-������ � � ���� � ���� ����������� ��� ������ - */ - int MaxSize=ReadSize-SearchLength+1; - int Increment=ReverseSearch ? -seek_size : +seek_size; + if (FirstChar) + { + Dlg.InitDialog(); + Dlg.Show(); + Dlg.ProcessKey(FirstChar); + } - for (int I=ReverseSearch ? MaxSize-1:0; I<MaxSize && I>=0; I+=Increment) - { - /* $ 01.08.2000 KM - ��������� ������ "Whole words" - */ - int locResultLeft=FALSE; - int locResultRight=FALSE; + Dlg.Process(); - if (WholeWords) - { - if (I) - { - if (IsSpace(Buf[I-1]) || IsEol(Buf[I-1]) || - (wcschr(Opt.strWordDiv,Buf[I-1]))) - locResultLeft=TRUE; - } - else - { - locResultLeft=TRUE; - } + if (Dlg.GetExitCode()!=SD_BUTTON_OK) + return; - if (ReadSize!=BufSize && I+SearchLength>=ReadSize) - locResultRight=TRUE; - else if (I+SearchLength<ReadSize && - (IsSpace(Buf[I+SearchLength]) || IsEol(Buf[I+SearchLength]) || - (wcschr(Opt.strWordDiv,Buf[I+SearchLength])))) - locResultRight=TRUE; - } - else - { - locResultLeft=TRUE; - locResultRight=TRUE; - } + SearchHex=SearchDlg[SD_RADIO_HEX].Selected; + Case=SearchDlg[SD_CHECKBOX_CASE].Selected; + WholeWords=SearchDlg[SD_CHECKBOX_WORDS].Selected; + ReverseSearch=SearchDlg[SD_CHECKBOX_REVERSE].Selected; + SearchRegexp=SearchDlg[SD_CHECKBOX_REGEXP].Selected; - if (!SearchHex) - { - Match = locResultLeft && locResultRight && strSearchStr.At(0) == Buf[I] && - ( SearchLength==1 || - ( strSearchStr.At(1) == Buf[I+1] && - (SearchLength==2 || !memcmp(strSearchStr.CPtr()+2,&Buf[I+2],(SearchLength-2)*sizeof(wchar_t))) - ) - ) - ; - } - else - { - if ((Match = search_bytes[0] == byte_buff[I+0]) && SearchLength > 1) - if ((Match = search_bytes[1] == byte_buff[I+1]) && SearchLength > 2) - if ((Match = search_bytes[2] == byte_buff[I+2]) && SearchLength > 3) - if ((Match = search_bytes[3] == byte_buff[I+3]) && SearchLength > 4) - Match = !memcmp(search_bytes+4, byte_buff+I+4, SearchLength-4); - } + if (SearchHex) + { + strSearchStr = SearchDlg[SD_EDIT_HEX].strData; + int len = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); + strSearchStr.Clear(); + ss2hex(strSearchStr, search_bytes, len, L' '); + } + else + { + strSearchStr = SearchDlg[SD_EDIT_TEXT].strData; + size_t pos = 0; + while (strSearchStr.Pos(pos, 0xffff)) + strSearchStr.Replace(pos, 1, L'\0'); + } + } - if (Match) + LastSearchCase = Case; + LastSearchWholeWords = WholeWords; + LastSearchReverse = ReverseSearch; + LastSearchRegexp = SearchRegexp; + + if (Next == -1) + ReverseSearch = !ReverseSearch; + + strMsgStr = strLastSearchStr = strSearchStr; + if (strMsgStr.GetLength()+18 > static_cast<DWORD>(ObjWidth)) + TruncStrFromEnd(strMsgStr, ObjWidth-18); + + sd.search_len = (int)strSearchStr.GetLength(); + if (0 != (LastSearchHex = SearchHex)) + { + sd.search_len = hex2ss(strSearchStr.CPtr(), search_bytes, ARRAYSIZE(search_bytes)); + sd.search_bytes = search_bytes; + sd.ch_size = 1; + Case = 1 + (WholeWords = SearchRegexp = 0); + searcher = (ReverseSearch ? &Viewer::search_hex_backward : &Viewer::search_hex_forward); + } + else + { + sd.is_utf8 = VM.CodePage == CP_UTF8; + sd.ch_size = getCharSize(VM.CodePage); + sd.search_text = strSearchStr.CPtr(); + + if ( SearchRegexp ) + { + WholeWords = 0; + searcher = (ReverseSearch ? &Viewer::search_regex_backward : &Viewer::search_regex_forward); + InsertRegexpQuote(strMsgStr); + sd.pRex = new RegExp; + string strSlash = strSearchStr; + InsertRegexpQuote(strSlash); + if ( !sd.pRex->Compile(strSlash, OP_PERLSTYLE | OP_OPTIMIZE | (Case ? 0 : OP_IGNORECASE)) ) + return; // wrong regular expression... + } + else + { + searcher = (ReverseSearch ? &Viewer::search_text_backward : &Viewer::search_text_forward); + InsertQuote(strMsgStr); + } + } + + if (!Case && !SearchRegexp) + { + strSearchStr.Upper(); + sd.search_text = strSearchStr.CPtr(); + } + + int found = 0; + + int search_direction = ReverseSearch ? -1 : +1; + switch (Next) + { + case 2: + StartSearchPos = LastSelectPos = (ReverseSearch ? FileSize : 0); + break; + case +1: case -1: + if ( SelectPos >= 0 && LastSelectSize >= 0 ) + { + if (sd.ch_size >= 1) + LastSelectPos = SelectPos + (ReverseSearch ? LastSelectSize-sd.ch_size : sd.ch_size); + else + { + INT64 prev_pos = SelectPos; + vseek(SelectPos, SEEK_SET); + for (;;) { - MatchPos = CurPos + I / seek_size; - if (t_utf8) + wchar_t ch; + bool ok_getc = vgetc(&ch); + LastSelectPos = vtell(); + if (!ReverseSearch || !ok_getc) + break; + if ( LastSelectPos >= SelectPos + LastSelectSize ) { - MatchPos = CurPos + GetStrBytesNum(t_Buf, I); - SearchLength = GetStrBytesNum(t_Buf+I, SearchLength); + LastSelectPos = prev_pos; + break; } - break; + prev_pos = LastSelectPos; } } + if (search_direction != LastSearchDirection) + StartSearchPos = LastSelectPos; + else if ( LastSelectPos == StartSearchPos ) // ������ � + found = -1; // ������������ - if ((ReverseSearch && CurPos <= 0) || (!ReverseSearch && veof())) - break; + break; + } // else pass to case 0 (below) + case 0: + LastSelectSize = SelectSize = -1; + StartSearchPos = LastSelectPos = (ReverseSearch ? EndOfScreen(0) : BegOfScreen()); + break; + } + LastSearchDirection = search_direction; - int asz = buf_size; - if (t_utf8) - asz = GetStrBytesNum(t_Buf, ReadSize); + if (!sd.search_len || (__int64)sd.search_len > FileSize) + return; - if (ReverseSearch) + sd.CurPos = LastSelectPos; + if ( !found ) + { + TPreRedrawFuncGuard preRedrawFuncGuard(PR_ViewerSearchMsg); + SetCursorType(FALSE,0); + + DWORD start_time = GetTickCount(); + for (;;) + { + found = (this->*searcher)(&sd); + if ( found != 0 ) + break; + + DWORD cur_time = GetTickCount(); + if ( cur_time - start_time > RedrawTimeout ) + { + start_time = cur_time; + + if (CheckForEscSilent()) { - /* $ 01.08.2000 KM - ������� �������� CurPos � ���� Whole words - */ - if (WholeWords) - CurPos -= asz/seek_size - SearchLength/seek_size + 1; - else - CurPos -= asz/seek_size - SearchLength/seek_size; + if (ConfirmAbortOp()) + { + Redraw(); + return; + } } - else + + int percent = -1; + INT64 done, total = FileSize; + if ( total > 0 ) { - if (WholeWords) - CurPos += asz/seek_size - SearchLength/seek_size + 1; + if ( !ReverseSearch ) + { + if ( sd.CurPos >= StartSearchPos ) + done = sd.CurPos - StartSearchPos; + else + done = (FileSize - StartSearchPos) + sd.CurPos; + } else - CurPos += asz/seek_size - SearchLength/seek_size; + { + if ( sd.CurPos <= StartSearchPos ) + done = StartSearchPos - sd.CurPos; + else + done = StartSearchPos + (FileSize - sd.CurPos); + } + percent = static_cast<int>(done*100/total); } + ViewerSearchMsg(strMsgStr, percent, SearchHex); } - - delete[] Buf; } } - if (Match) + if ( sd.MatchPos >= 0 ) { - /* $ 24.01.2003 KM - ! �� �������� ������ �������� �� ���� ������ �� - ���� ������������ ����. - */ - SelectText(MatchPos,SearchLength,ReverseSearch?0x2:0); - // ������� ��������� �� ��������� ����� ������ �� ����. + SelectText(sd.MatchPos, sd.search_len, ReverseSearch?0x2:0); + LastSelectSize = SelectSize; + + // ������� ��������� �� ��������� �������� ������ �� ����. int FromTop=(ScrY-(Opt.ViOpt.ShowKeyBar?2:1))/4; if (FromTop<0 || FromTop>ScrY) FromTop=0; - for (int i=0; i<FromTop; i++) - Up(); + Up(FromTop); AdjustSelPosition = TRUE; Show(); @@ -2598,24 +3264,13 @@ } else { - //Show(); - /* $ 27.01.2003 VVM - + ����� ������� ������ ������� � ������� ������ � �����/���� */ - if (SearchFlags.Check(SEARCH_MODE2)) - { - Message(MSG_WARNING,1,MSG(MViewSearchTitle), - (SearchHex?MSG(MViewSearchCannotFindHex):MSG(MViewSearchCannotFind)),strMsgStr,MSG(MOk)); - } - else - { - if (!Message(MSG_WARNING,2,MSG(MViewSearchTitle), - (SearchHex?MSG(MViewSearchCannotFindHex):MSG(MViewSearchCannotFind)),strMsgStr, - (ReverseSearch?MSG(MViewSearchFromEnd):MSG(MViewSearchFromBegin)), - MSG(MHYes),MSG(MHNo))) - { - Search(2,0); - } - } + Message( + MSG_WARNING, 1, + MSG(MViewSearchTitle), + (SearchHex ? MSG(MViewSearchCannotFindHex) : MSG(MViewSearchCannotFind)), + strMsgStr, + MSG(MOk) + ); } } @@ -2625,37 +3280,31 @@ 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; @@ -2663,7 +3312,6 @@ ConsoleTitle::SetFarTitle(strTitle); } - void Viewer::SetTempViewName(const wchar_t *Name, BOOL DeleteFolder) { if (Name && *Name) @@ -2677,7 +3325,6 @@ Viewer::DeleteFolder=DeleteFolder; } - void Viewer::SetTitle(const wchar_t *Title) { if (!Title) @@ -2686,19 +3333,16 @@ 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) @@ -2825,10 +3469,15 @@ if (IsUnicodeCodePage(VM.CodePage)) { - Reader.Read(Buf, Count*2, &ReadSize); + int rev = (CP_REVERSEBOM == VM.CodePage ? 1 : 0); + + Reader.Read(Buf, Count, &ReadSize); if (0 != (ReadSize & 1)) - ((char *)Buf)[ReadSize++] = '\0'; - + { + ((char *)Buf)[ReadSize-1+rev] = (char)(REPLACE_CHAR & 0xff); + ((char *)Buf)[ReadSize-0-rev] = (char)(REPLACE_CHAR >> 8); + ++ReadSize; + } if (CP_REVERSEBOM == VM.CodePage) { for (DWORD i=0; i<ReadSize; i+=2) @@ -2838,7 +3487,6 @@ ((char *)Buf)[i+1] = t; } } - ReadSize /= 2; } else @@ -2871,15 +3519,11 @@ bool Viewer::vseek(__int64 Offset, int Whence) { - int seek_size = IsUnicodeCodePage(VM.CodePage) ? 2 : 1; - Offset *= seek_size; - if (FILE_CURRENT == Whence) { if (vgetc_ready) { int tail = vgetc_cb - vgetc_ib; - tail += (seek_size - 1) * (tail & 1); Offset += tail; vgetc_ready = false; } @@ -2898,9 +3542,6 @@ if (vgetc_ready) Ptr -= (vgetc_cb - vgetc_ib); - if (IsUnicodeCodePage(VM.CodePage)) - Ptr=(Ptr+(Ptr&1))/2; - return Ptr; } @@ -2927,9 +3568,6 @@ DWORD nr = 0; Reader.Read(vgetc_buffer + vgetc_cb, (DWORD)(ARRAYSIZE(vgetc_buffer)-vgetc_cb), &nr); vgetc_cb += (int)nr; - - if (0 != (vgetc_cb & 1) && IsUnicodeCodePage(VM.CodePage)) - vgetc_buffer[vgetc_cb++] = 0; } vgetc_ready = true; @@ -2951,11 +3589,17 @@ switch (VM.CodePage) { case CP_REVERSEBOM: - *pCh = (wchar_t)((vgetc_buffer[vgetc_ib] << 8) | vgetc_buffer[vgetc_ib+1]); + if (vgetc_ib == vgetc_cb-1) + *pCh = REPLACE_CHAR; + else + *pCh = (wchar_t)((vgetc_buffer[vgetc_ib] << 8) | vgetc_buffer[vgetc_ib+1]); vgetc_ib += 2; break; case CP_UNICODE: - *pCh = (wchar_t)((vgetc_buffer[vgetc_ib+1] << 8) | vgetc_buffer[vgetc_ib]); + if (vgetc_ib == vgetc_cb-1) + *pCh = REPLACE_CHAR; + else + *pCh = (wchar_t)((vgetc_buffer[vgetc_ib+1] << 8) | vgetc_buffer[vgetc_ib]); vgetc_ib += 2; break; case CP_UTF8: @@ -2978,6 +3622,54 @@ return true; } +wchar_t Viewer::vgetc_prev() +{ + INT64 pos = vtell(); + if ( pos <= 0 ) + return L'\0'; + + int ch_size = getCharSize(VM.CodePage); + if ( pos < ch_size ) + return REPLACE_CHAR; + + int nb = (ch_size >= 1 ? ch_size : (pos > 4 ? 4 : static_cast<int>(pos))); + DWORD nr = 0; + + char ss[4]; + if ( vseek(-nb, SEEK_CUR) ) + Reader.Read(ss, static_cast<DWORD>(nb), &nr); + + vseek(pos, SEEK_SET); + + wchar_t ch = REPLACE_CHAR; + if ( static_cast<int>(nr) == nb ) + { + switch ( VM.CodePage ) + { + case CP_REVERSEBOM: + ch = MAKEWORD(ss[1], ss[0]); + break; + case CP_UNICODE: + ch = MAKEWORD(ss[0], ss[1]); + break; + case CP_UTF8: + { + int tail = 0; + wchar_t w[4]; + int nw = utf8_to_WideChar(ss, nb, w,nullptr, 4,tail); + if ( !tail && nw > 0 ) + ch = w[nw-1]; + break; + } + default: + MultiByteToWideChar(VM.CodePage, 0, (LPCSTR)ss,1, &ch,1); + break; + } + } + return ch; +} + + #define RB_PRC 3 #define RB_HEX 4 #define RB_DEC 5 @@ -3060,9 +3752,6 @@ // Percent=0; Offset=FileSize/100*Percent; - if (IsUnicodeCodePage(VM.CodePage)) - Offset*=2; - while (ToPercent64(Offset,FileSize)<Percent) Offset++; } @@ -3094,31 +3783,16 @@ // Percent=0; Offset=FileSize/100*Percent; - if (IsUnicodeCodePage(VM.CodePage)) - Offset*=2; - while (ToPercent64(Offset,FileSize)<Percent) Offset++; } } - if (Relative) - { - if (Relative==-1 && Offset>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; // ��� ��� ����� ����� ���� + FilePos = (Relative ? FilePos + Offset*Relative : Offset); + FilePos = (FilePos < 0 ? 0 : (FilePos > FileSize ? FileSize : FilePos)); } - // ������� AdjustFilePos(); -// LastSelPos=FilePos; if (!(Flags&VSP_NOREDRAW)) Show(); } @@ -3129,6 +3803,9 @@ if (!VM.Hex) { + int ch_size = getCharSize(VM.CodePage); + FilePos -= FilePos % ch_size; + vseek(FilePos, SEEK_SET); if (VM.CodePage != CP_UTF8) { @@ -3140,7 +3817,7 @@ if (vgetc_ib < vgetc_cb) { if (0x80 == (vgetc_buffer[vgetc_ib] & 0xC0)) - { + { if (++vgetc_ib < vgetc_cb) { if (0x80 == (vgetc_buffer[vgetc_ib] & 0xC0)) @@ -3152,18 +3829,18 @@ } } } - } + } else - { + { vgetc(&ch); } } } - FilePos = vtell(); - Up(); - } + FilePos = vtell(); + Up(1); } +} void Viewer::SetFileSize() { @@ -3173,13 +3850,6 @@ UINT64 uFileSize=0; // BUGBUG, sign ViewFile.GetSize(uFileSize); FileSize=uFileSize; - - /* $ 20.02.2003 IS - ����� ���������� FilePos � FileSize, FilePos �� ������� ������ - �������� � ��� ����, ������ FileSize ���� ���� ������ - */ - if (IsUnicodeCodePage(VM.CodePage)) - FileSize=(FileSize+(FileSize&1))/2; } @@ -3190,85 +3860,50 @@ Flags=SelectFlags; } -/* $ 19.01.2001 SVS - �������� - � ������� ������������� ������. - Flags=0x01 - �������� (����� Show()) - 0x02 - "������� �����" ? -*/ -void Viewer::SelectText(const __int64 &MatchPos,const __int64 &SearchLength, const DWORD Flags) +// Flags=0x01 - �������� [����� Show()] +// 0x02 - "������� �����" ? +// +void Viewer::SelectText(const __int64 &match_pos,const __int64 &search_len, const DWORD flags) { if (!ViewFile.Opened()) return; - int buff_size = 1024; - wchar_t *Buf = Up_buffer, *tBuf = (!VM.Hex && VM.CodePage == CP_UTF8) ? Buf + buff_size : nullptr; - __int64 StartLinePos = -1, SearchLinePos = MatchPos - buff_size; - if (SearchLinePos < 0) - { - buff_size += (int)SearchLinePos; - SearchLinePos = 0; - } + SelectPos = match_pos; + SelectSize = search_len; + SelectFlags = flags; + if ( SelectSize < 0 ) + return; - vseek(SearchLinePos, SEEK_SET); - int ReadSize = vread(Buf, buff_size, tBuf); - - for (int I=ReadSize-1; I >= 0; I--) - if (Buf[I]==L'\n' || Buf[I]==L'\r') + if ( VM.Hex ) { - if (tBuf) - StartLinePos = MatchPos - GetStrBytesNum(tBuf+I, ReadSize-I); - else - StartLinePos = SearchLinePos+I; - break; + FilePos = (FilePos & 0xf) | (SelectPos & ~0xf); + FilePos = (FilePos < SelectPos ? FilePos : (FilePos > 16 ? FilePos-16 : 0)); } - - vseek(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) + FilePos = SelectPos; + Up(1); + LeftPos = 0; + + if ( !VM.Wrap ) { - Up(); - Show(); //update OutStr - } + vseek(vString.nFilePos = FilePos, SEEK_SET); + vString.lpData[0] = L'\0'; + ReadString(&vString, (int)(SelectPos-FilePos)); - /* $ 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; + wchar_t first_found_char = L'\0'; + vgetc(&first_found_char); - if (VM.Wrap) - Length%=Width+1; //?? - - if (Length<=Width) - LeftPos=0; - - if (Length-LeftPos>Width || Length<LeftPos) - { - LeftPos=Length; - - if (LeftPos>(MAX_VIEWLINE-1) || LeftPos<0) - LeftPos=0; - else if (LeftPos>10) - LeftPos-=10; + if ( L'\r' != first_found_char && L'\n' != first_found_char ) + { + int found_offset = (int)wcslen(vString.lpData); + if ( found_offset > Width-10 ) + LeftPos = (Width <= 10 ? found_offset : found_offset + 10 - Width); + } } } - if (Flags&1) + if (0 != (flags & 1)) { AdjustSelPosition = TRUE; Show(); @@ -3276,6 +3911,7 @@ } } + int Viewer::ViewerControl(int Command,void *Param) { switch (Command) @@ -3365,7 +4001,7 @@ } else { - SelectSize = 0; + SelectSize = -1; Show(); } @@ -3476,7 +4112,6 @@ Show(); } -// LastSelPos=FilePos; return oldHex; } @@ -3488,7 +4123,7 @@ if (VM.Wrap) LeftPos = 0; - if (!VM.Wrap) + if (!VM.Hex) AdjustFilePos(); if (isRedraw) @@ -3498,7 +4133,6 @@ } Opt.ViOpt.ViewerIsWrap=VM.Wrap; -// LastSelPos=FilePos; return oldWrap; } @@ -3513,6 +4147,9 @@ LeftPos = 0; } + if (!VM.Hex) + AdjustFilePos(); + if (isRedraw) { ChangeViewKeyBar(); @@ -3520,6 +4157,5 @@ } Opt.ViOpt.ViewerWrap=VM.WordWrap; -//LastSelPos=FilePos; return oldTypeWrap; } Index: config.hpp =================================================================== --- config.hpp (revision 6286) +++ config.hpp (working copy) @@ -314,6 +314,8 @@ int AnsiCodePageAsDefault; int ShowTitleBar; int SearchRegexp; + int MaxLineSize; // 80..16384, default=2048 + int SearchEditFocus; // auto-focus on edit text/hex window }; // "�����" Index: config.cpp =================================================================== --- config.cpp (revision 6286) +++ config.cpp (working copy) @@ -595,6 +595,9 @@ {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"PersistentBlocks",&Opt.ViOpt.PersistentBlocks,0, 0}, {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"AnsiCodePageAsDefault",&Opt.ViOpt.AnsiCodePageAsDefault,1, 0}, + {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"MaxLineSize",&Opt.ViOpt.MaxLineSize,2048, 0}, + {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"SearchEditFocus",&Opt.ViOpt.SearchEditFocus,0, 0}, + {1, GeneralConfig::TYPE_INTEGER, NKeyDialog, L"EditHistory",&Opt.Dialogs.EditHistory,1, 0}, {1, GeneralConfig::TYPE_INTEGER, NKeyDialog, L"EditBlock",&Opt.Dialogs.EditBlock,0, 0}, {1, GeneralConfig::TYPE_INTEGER, NKeyDialog, L"AutoComplete",&Opt.Dialogs.AutoComplete,1, 0}, @@ -920,8 +923,15 @@ } } - Opt.ViOpt.ViewerIsWrap&=1; - Opt.ViOpt.ViewerWrap&=1; + Opt.ViOpt.ViewerIsWrap &= 1; + Opt.ViOpt.ViewerWrap &= 1; + if (!Opt.ViOpt.MaxLineSize) + Opt.ViOpt.MaxLineSize = 2048; + else if (Opt.ViOpt.MaxLineSize < 80) + Opt.ViOpt.MaxLineSize = 80; + else if (Opt.ViOpt.MaxLineSize > 16*1024) + Opt.ViOpt.MaxLineSize = 16*1024; + Opt.ViOpt.SearchEditFocus &= 1; // ������� �������� �������� ������������ ;-) if (Opt.strWordDiv.IsEmpty()) |
|
а че за исправления? + куда то пропала строка #include "RegExp.hpp" |
|
http://skirda-file.googlecode.com/files/Viewer-new.3.7z |
|
Так, если все устраивает тестовый вариант, то перед коммитом хотелось бы увидеть строки для changelog - что значит "новый вьювер" :-) |
|
скобка была не на месте. новый... Внутренности: полностью переделан поиск добавлен механизм кеширования переводов строк юникодные файлы теперь как все прочие (нет размеру в символах!) переделан HexView переработан диалог поиска Функции: добавлен поиск регулярных выражений (построчный в обе стороны) повторный поиск всегда зациклен до места начала поиска или смены направления добавлена возможность изменения максимальной длины строки (параметр) ну и порядка 30% кода переписано... |
|
> добавлена возможность изменения максимальной длины строки (параметр) Это где? Опция доступна простым смертным? (из интерфейса, или она столь специфичная, что для большинства случаев хватит 2048?) Если нет, то в FARConfig нужно нули выставить для "MaxLineSize" и "SearchEditFocus": {0, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"MaxLineSize",&Opt.ViOpt.MaxLineSize,2048, 0}, {0, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"SearchEditFocus",&Opt.ViOpt.SearchEditFocus,0, 0}, |
|
в интерфейсе нет. 2048 - текущее значение. при нуле тоже будет 2048. в конфиг добавлен код: if (!Opt.ViOpt.MaxLineSize) Opt.ViOpt.MaxLineSize = 2048; else if (Opt.ViOpt.MaxLineSize < 80) Opt.ViOpt.MaxLineSize = 80; else if (Opt.ViOpt.MaxLineSize > 16*1024) Opt.ViOpt.MaxLineSize = 16*1024; |
|
build 2054 |
|
> 2048 - текущее значение А почему бы не сделать дефолтное значение побольше, например раз в 10? |
|
пока ограничено 16k (16k*2 - это половина размера кэша CacheRead, можно увеличить и то и другое). если длинные строки нужны всем - не проблема, я просто по дефолту оставлял текущее поведение. |
|
ViewerLongLineFix.diff (7,088 bytes)
Index: config.hpp =================================================================== --- config.hpp (revision 6306) +++ config.hpp (working copy) @@ -300,6 +300,13 @@ */ struct ViewerOptions { + enum EViewerLineSize + { + eMinLineSize = 100, + eDefLineSize = 10*1000, + eMaxLineSize = 100*1000 + }; + int TabSize; int AutoDetectCodePage; int ShowScrollbar; // $ 18.07.2000 tran ���� �������� �� viewer @@ -314,7 +321,7 @@ int AnsiCodePageAsDefault; int ShowTitleBar; int SearchRegexp; - int MaxLineSize; // 80..16384, default=2048 + int MaxLineSize; // 100..100000, default=10000 int SearchEditFocus; // auto-focus on edit text/hex window }; Index: config.cpp =================================================================== --- config.cpp (revision 6306) +++ config.cpp (working copy) @@ -595,7 +595,7 @@ {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"PersistentBlocks",&Opt.ViOpt.PersistentBlocks,0, 0}, {1, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"AnsiCodePageAsDefault",&Opt.ViOpt.AnsiCodePageAsDefault,1, 0}, - {0, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"MaxLineSize",&Opt.ViOpt.MaxLineSize,2048, 0}, + {0, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"MaxLineSize",&Opt.ViOpt.MaxLineSize,ViewerOptions::eDefLineSize, 0}, {0, GeneralConfig::TYPE_INTEGER, NKeyViewer,L"SearchEditFocus",&Opt.ViOpt.SearchEditFocus,0, 0}, {1, GeneralConfig::TYPE_INTEGER, NKeyDialog, L"EditHistory",&Opt.Dialogs.EditHistory,1, 0}, @@ -926,11 +926,11 @@ Opt.ViOpt.ViewerIsWrap &= 1; Opt.ViOpt.ViewerWrap &= 1; if (!Opt.ViOpt.MaxLineSize) - Opt.ViOpt.MaxLineSize = 2048; - else if (Opt.ViOpt.MaxLineSize < 80) - Opt.ViOpt.MaxLineSize = 80; - else if (Opt.ViOpt.MaxLineSize > 16*1024) - Opt.ViOpt.MaxLineSize = 16*1024; + Opt.ViOpt.MaxLineSize = ViewerOptions::eDefLineSize; + else if (Opt.ViOpt.MaxLineSize < ViewerOptions::eMinLineSize) + Opt.ViOpt.MaxLineSize = ViewerOptions::eMinLineSize; + else if (Opt.ViOpt.MaxLineSize > ViewerOptions::eMaxLineSize) + Opt.ViOpt.MaxLineSize = ViewerOptions::eMaxLineSize; Opt.ViOpt.SearchEditFocus &= 1; // ������� �������� �������� ������������ ;-) Index: cache.hpp =================================================================== --- cache.hpp (revision 6306) +++ cache.hpp (working copy) @@ -35,7 +35,7 @@ class CachedRead { public: - CachedRead(File& file); + CachedRead(File& file, DWORD buffer_size=0); ~CachedRead(); bool AdjustAlignment(); // file have to be opened already bool Read(LPVOID Data, DWORD DataSize, LPDWORD BytesRead); Index: cache.cpp =================================================================== --- cache.cpp (revision 6306) +++ cache.cpp (working copy) @@ -35,22 +35,21 @@ #include "cache.hpp" -CachedRead::CachedRead(File& file): - Buffer(static_cast<LPBYTE>(xf_malloc(DefaultBufferSize))), +CachedRead::CachedRead(File& file, DWORD buffer_size): file(file), ReadSize(0), BytesLeft(0), LastPtr(0), BufferSize(DefaultBufferSize), Alignment(512) -{} +{ + BufferSize = (buffer_size ? (buffer_size+Alignment-1) & ~(Alignment-1) : DefaultBufferSize); + Buffer = static_cast<LPBYTE>(xf_malloc(BufferSize)); +} CachedRead::~CachedRead() { - if (Buffer) - { - xf_free(Buffer); - } + xf_free(Buffer); } bool CachedRead::AdjustAlignment() Index: viewer.hpp =================================================================== --- viewer.hpp (revision 6306) +++ viewer.hpp (working copy) @@ -159,6 +159,10 @@ int lcache_wwrap; int lcache_width; + int max_backward_size; + int llengths_size; + int *llengths; + wchar_t *Search_buffer; int Search_buffer_size; Index: viewer.cpp =================================================================== --- viewer.cpp (revision 6306) +++ viewer.cpp (working copy) @@ -82,7 +82,7 @@ Viewer::Viewer(bool bQuickView, UINT aCodePage): ViOpt(Opt.ViOpt), - Reader(ViewFile), + Reader(ViewFile, (Opt.ViOpt.MaxLineSize*2*64 > 64*1024 ? Opt.ViOpt.MaxLineSize*2*64 : 64*1024)), m_bQuickView(bQuickView) { _OT(SysLog(L"[%p] Viewer::Viewer()", this)); @@ -135,15 +135,23 @@ vgetc_cb = vgetc_ib = 0; vgetc_composite = L'\0'; - vread_buffer = new char[vread_buffer_size = 8192]; + vread_buffer_size = (MAX_VIEWLINEB < 8192 ? 8192 : MAX_VIEWLINEB); + vread_buffer = new char[vread_buffer_size]; lcache_first = lcache_last = -1; - lcache_lines = new INT64[lcache_size = 8*1000]; + lcache_lines = new INT64[lcache_size = 16*1000]; lcache_count = 0; lcache_base = 0; lcache_ready = false; lcache_wrap = lcache_wwrap = lcache_width = -1; + int cached_buffer_size = (Opt.ViOpt.MaxLineSize*2*64 > 64*1024 ? Opt.ViOpt.MaxLineSize*2*64 : 64*1024); + max_backward_size = ViewerOptions::eMaxLineSize*3; + if ( max_backward_size > cached_buffer_size/2 ) + max_backward_size = cached_buffer_size / 2; + llengths_size = max_backward_size / 40; + llengths = new int[llengths_size]; + Search_buffer_size = 3 * (MAX_VIEWLINEB < 8000 ? 8000 : MAX_VIEWLINEB); Search_buffer = new wchar_t[Search_buffer_size]; @@ -183,6 +191,7 @@ delete[] vString.lpData; delete[] Search_buffer; + delete[] llengths; delete[] lcache_lines; delete[] vread_buffer; @@ -2003,8 +2012,7 @@ } } - static const int portion_size = 256; - static const int max_backward = 32*1024; + const int portion_size = 256; union { char c1[portion_size]; @@ -2012,7 +2020,6 @@ } buff; int j, buff_size, nr, ch_size = getCharSize(VM.CodePage); - int len[max_backward/40]; // suppose minimum line with is 80 chars... while ( nlines > 0 ) { @@ -2026,7 +2033,7 @@ // backward CR-LF search // - for ( j = 0; j < max_backward/portion_size; ++j ) + for ( j = 0; j < max_backward_size/portion_size; ++j ) { buff_size = (fpos > (__int64)portion_size ? portion_size : (int)fpos); fpos -= buff_size; @@ -2096,23 +2103,23 @@ // split read portion // vseek(vString.nFilePos = fpos, SEEK_SET); - for (i = 0; i < (int)ARRAYSIZE(len); ++i) + for (i = 0; i < llengths_size; ++i) { ReadString(&vString, -1, false); - len[i] = (vString.have_eol ? -1 : +1) * vString.linesize; + llengths[i] = (vString.have_eol ? -1 : +1) * vString.linesize; if ((vString.nFilePos += vString.linesize) >= fpos1) { fpos1 = vString.nFilePos; break; } } - assert(i < (int)ARRAYSIZE(len)); - if (i >= (int)ARRAYSIZE(len)) + assert(i < llengths_size); + if (i >= llengths_size) --i; while ( i >= 0 ) { - int l = len[i--]; + int l = llengths[i--]; bool eol = false; if (l < 0) { @@ -3889,7 +3896,7 @@ { vseek(vString.nFilePos = FilePos, SEEK_SET); vString.lpData[0] = L'\0'; - ReadString(&vString, (int)(SelectPos-FilePos)); + ReadString(&vString, (int)(SelectPos-FilePos), false); wchar_t first_found_char = L'\0'; vgetc(&first_found_char); |
|
fix для длинных строк (поправлены ошибки + MaxLineSize: Min=100, Def=10000, Max=100000) |
|
build 2061 |
|
NewViewer-fix2.diff (831 bytes)
Index: viewer.cpp =================================================================== --- viewer.cpp (revision 6365) +++ viewer.cpp (working copy) @@ -254,6 +254,7 @@ ViewFile.Close(); Reader.Clear(); + vgetc_ready = lcache_ready = false; SelectSize = -1; // ������� �������� strFileName = Name; @@ -3965,12 +3966,7 @@ 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); + GoTo(FALSE, vsp->StartPos, vsp->Flags); if (isReShow && !(vsp->Flags&VSP_NOREDRAW)) ScrBuf.Flush(); |
|
2 небольшие правки: 1) сброс кэша переводов строк при переключении файлов по +/- 2) удаление остатков 'символьного' размера юникодных файлов |
|
2083 |
|
ViewerAutoscrollAgain.diff (612 bytes)
Index: viewer.cpp =================================================================== --- viewer.cpp (revision 6548) +++ viewer.cpp (working copy) @@ -1266,6 +1266,8 @@ if (!apiGetFindDataEx(strFullFileName, NewViewFindData)) return TRUE; + ViewFile.GetSize(NewViewFindData.nFileSize); // Required! -- thanks Dzirt2005 + if (ViewFindData.ftLastWriteTime.dwLowDateTime!=NewViewFindData.ftLastWriteTime.dwLowDateTime || ViewFindData.ftLastWriteTime.dwHighDateTime!=NewViewFindData.ftLastWriteTime.dwHighDateTime || ViewFindData.nFileSize != NewViewFindData.nFileSize) |
|
Ёще одна поправка для автоскролла. 'Лишний' код оказался нужным. Спасибо Dzirt2005 за диагностику. Проявлялось, если вывод батника перенаправить в просматриваемый файл. |
|
build 2143 |
|
А давайте во вьювер режим дампа добавим? Т.е. без обработки переносов строк и табуляций. |
|
а подробнее... 0) зачем? 1) что делать с длинными строками? 2) управление (вкл-выкл) ? |
|
Мне тоже часто хочется такое. Типа HEX'а, но без HEX'а. Просто чтобы на экран влезал кусок дампа побольше. |
|
0) иногда надо смотреть/искать строковые данные в бинарном файле, внезапные переносы при этом бессмысленны, а 16-символьная колонка в hex - сильно узко. 1) как сейчас 2) F4, циклично: text - hex - dump |
|
<CR>, <LF> - обычные (видимые) символы, или переход на новую строку? |
|
>> 1) что делать с длинными строками? > 1) как сейчас хотя, наверное, в этом режиме лучше просто всегда сворачивать по размеру окна. > <CR>, <LF> - обычные (видимые) символы, или переход на новую строку? видимые, всё как в текстовой колонке hex-режима. |
|
можно сделать, несложно. imho лучше конфигурить доступность этого режима. но я смогу этим заняться только недели через 2, сейчас совсем нет времени. |
|
AutoscrollOptimize.diff (2,262 bytes)
Index: viewer.cpp =================================================================== --- viewer.cpp (revision 6635) +++ viewer.cpp (working copy) @@ -1265,36 +1265,45 @@ if (!apiGetFindDataEx(strFullFileName, NewViewFindData)) return TRUE; - ViewFile.GetSize(NewViewFindData.nFileSize); // Required! -- thanks Dzirt2005 - - if (ViewFindData.ftLastWriteTime.dwLowDateTime!=NewViewFindData.ftLastWriteTime.dwLowDateTime - || ViewFindData.ftLastWriteTime.dwHighDateTime!=NewViewFindData.ftLastWriteTime.dwHighDateTime - || ViewFindData.nFileSize != NewViewFindData.nFileSize) + // Smart file change check -- thanks Dzirt2005 + // + bool changed = ( + ViewFindData.ftLastWriteTime.dwLowDateTime!=NewViewFindData.ftLastWriteTime.dwLowDateTime || + ViewFindData.ftLastWriteTime.dwHighDateTime!=NewViewFindData.ftLastWriteTime.dwHighDateTime || + ViewFindData.nFileSize != NewViewFindData.nFileSize + ); + if ( changed ) + ViewFindData = NewViewFindData; + else { + if ( !ViewFile.GetSize(NewViewFindData.nFileSize) || FileSize == static_cast<__int64>(NewViewFindData.nFileSize) ) + return TRUE; + changed = FileSize > static_cast<__int64>(NewViewFindData.nFileSize); // true if file shrank + } + + SetFileSize(); + if ( changed ) // do not reset caches if file just enlarged [make sense on Win7, doesn't matter on XP] { - ViewFindData = NewViewFindData; - SetFileSize(); - Reader.Clear(); // ���� ���� �� ��� ����? ViewFile.FlushBuffers(); vseek(0, SEEK_CUR); // reset vgetc state lcache_ready = false; // reset start-lines cache + } - if (FilePos>FileSize) + if (FilePos > FileSize) + { + ProcessKey(KEY_CTRLEND); + } + else + { + __int64 PrevLastPage=LastPage; + LastPage = 0; + Show(); + + if (PrevLastPage && !LastPage) { ProcessKey(KEY_CTRLEND); + LastPage=TRUE; } - else - { - __int64 PrevLastPage=LastPage; - LastPage = 0; - Show(); - - if (PrevLastPage && !LastPage) - { - ProcessKey(KEY_CTRLEND); - LastPage=TRUE; - } - } } } |
|
Оптимизация автоскролла для Win7. Не сбрасываем кеш, если файл просто растёт. На XP эффект почти нулевой. |
|
build 2178 |
|
стал замечать, что вьювер последних версий стал некорректно отображать первые строки при включенной опции [x] Save view and edit history. замечаю на файле changelog, т.е. смотрю его для текущей ревизии, через несколько дней делаю "svn up", открываем на просмотр файл changelog - первые строки на экране непонятно как плавают. делаем Home и переоткрытие - становится потребно. |
|
AdjustFilePos.diff (301 bytes)
Index: viewer.cpp =================================================================== --- viewer.cpp (revision 6675) +++ viewer.cpp (working copy) @@ -330,6 +330,8 @@ CachedCodePage = 0; LastSelectPos=FilePos=NewFilePos; LeftPos=NewLeftPos; + + AdjustFilePos(); } else { |
|
AdjustFilePos.diff |
|
гораздо лучше. |
|
build 2195 |
|
AdjustFilePos2.diff (598 bytes)
Index: viewer.cpp =================================================================== --- viewer.cpp (revision 6734) +++ viewer.cpp (working copy) @@ -330,8 +330,6 @@ CachedCodePage = 0; LastSelectPos=FilePos=NewFilePos; LeftPos=NewLeftPos; - - AdjustFilePos(); } else { @@ -362,6 +360,7 @@ if (Detect) { VM.CodePage=CodePage; + //??? CodePageChangedByUser=TRUE; } if (CachedCodePage) @@ -384,6 +383,8 @@ if (FilePos > FileSize) FilePos=0; + if ( FilePos ) + AdjustFilePos(); ChangeViewKeyBar(); AdjustWidth(); |
|
AdjustFilePos2 - поправка к предыдущему фиксу. Позицию надо корректировать после установки кодовой страницы. Иначе при просмотре юникода у вьювера может поехать крыша :) 10x Maximus: http://forum.farmanager.com/viewtopic.php?f=9&t=667&start=15#p85644 |
|
build 2206 |
|
AdjustFilePos3.diff (1,005 bytes)
Index: viewer.cpp =================================================================== --- viewer.cpp (revision 6747) +++ viewer.cpp (working copy) @@ -1432,6 +1432,7 @@ { VM.CodePage = VM.CodePage==GetOEMCP() ? GetACP() : GetOEMCP(); lcache_ready = false; + AdjustFilePos(); ChangeViewKeyBar(); Show(); CodePageChangedByUser=TRUE; @@ -1440,8 +1441,6 @@ case KEY_SHIFTF8: { UINT nCodePage = SelectCodePage(VM.CodePage, true, true, false, true); - lcache_ready = false; - if (nCodePage != static_cast<UINT>(-1)) { if (nCodePage == (CP_AUTODETECT & 0xffff)) @@ -1454,7 +1453,8 @@ } CodePageChangedByUser=TRUE; VM.CodePage=nCodePage; - SetFileSize(); + lcache_ready = false; + AdjustFilePos(); ChangeViewKeyBar(); Show(); } @@ -3382,6 +3382,7 @@ void Viewer::SetFilePos(__int64 Pos) { FilePos=Pos; + AdjustFilePos(); }; void Viewer::SetPluginData(const wchar_t *PluginData) |
|
Ещё пара мест где надо корректировать позицию - при смене кодировки и при выставлении позиции через интерфейс. Спасибо .1st за диагностику. |
|
build 2210 |
|
версию с дамповым режимом просмотра можно попробовать: http://sharapov-16.narod.ru/far/index.html |
|
ну так кому-нибудь такой режим ещё нужен? или в морг? |
|
Нужен. |
|
Пригодится! |
|
как по мне, так дополнительная опция и ненужна, сделать по-умолчанию: текст-хекс-дамп |
|
Нужны мнения... В текущей версии вьювер при переключении в текстовый режим автоматически позиционируется на начало текущей строки. Некоторые считают это багом. Для бинарных файлов для этого есть некоторые основания. В связи с этим хочу ввести небольшой интеллект: для бинарных файлов по F4 переключаем хекс-дамп, для текстовых текст-хекс. По Shift-F4 все режимы по очереди. |
|
Может, по Shift-F4 - менюшку, со списком режимов? Тогда можно будет намакросить любой вариант переключений... |
|
WWrap.diff (1,811 bytes)
Index: viewer.cpp =================================================================== --- viewer.cpp (revision 6761) +++ viewer.cpp (working copy) @@ -962,29 +962,40 @@ } pString->lpData[OutPtr++] = ch ? ch : L' '; - if (!VM.Wrap) + if ( !VM.Wrap ) continue; - if (OutPtr >= Width) + if ( VM.WordWrap && OutPtr <= Width && wrapped_char(ch) >= 0 ) { - if (VM.WordWrap && wrap_out > 0) - { - OutPtr = wrap_out; - vseek(wrap_pos, SEEK_SET); - while (OutPtr > 0 && is_space_or_nul(pString->lpData[OutPtr-1])) - --OutPtr; - skip_space = true; - } - break; + wrap_out = OutPtr; + wrap_pos = fpos1; } - if (!VM.WordWrap) + if ( OutPtr < Width ) continue; + if ( !VM.WordWrap ) + break; - if (wrapped_char(ch) >= 0) + if ( OutPtr > Width ) { - wrap_out = OutPtr; - wrap_pos = vtell(); + if ( wrap_out <= 0 || is_space_or_nul(ch) ) + { + wrap_out = OutPtr - 1; + wrap_pos = fpos; + } + + OutPtr = wrap_out; + vseek(wrap_pos, SEEK_SET); + while (OutPtr > 0 && is_space_or_nul(pString->lpData[OutPtr-1])) + --OutPtr; + + if ( bSelEndFound && pString->nSelEnd > OutPtr ) + pString->nSelEnd = OutPtr; + if ( bSelStartFound && pString->nSelStart >= OutPtr ) + bSelStartFound = bSelEndFound = false; + + skip_space = true; + break; } } @@ -2248,9 +2259,9 @@ struct MyDialogData { - Viewer *viewer; + Viewer *viewer; bool edit_autofocus; - bool hex_mode; + bool hex_mode; bool recursive; }; @@ -2279,7 +2290,7 @@ } case DM_SDREXVISIBILITY: { - int show = 1; + int show = 1; if ( Param1 ) { int tlen = (int)SendDlgMessage(hDlg, DM_GETTEXTPTR, SD_EDIT_TEXT, 0); |
|
WWrap.diff - убираем артефакты при попадании найденного текста в переносимую часть строки при WWrap. Более точно определяем границу переноса (раньше переносилось 'с запасом'). |
|
2useven10: давай так поступим. я переписываю этот Инц на тебя, а дальше сам :-) ты уже можешь сюда не аттачить дифы. в этом Инце ты ставишь "нужен отклик" и пишешь номер билда, где ЭТО исправлено. тот, что проверяет (хмм.. в этом случае ты :-)) ставит статус "угу, исправлено"... Я так думаю, что этот Инц имеет смысл закрыть, т.к. свою роль он уже сыграл, но начинает обрастать прочими хотелкобагофичами. Те, кто/кому/etc. что-то надо от вьювера - пусть заводят новые Инцы. |
|
build 2217 |
Date Modified | Username | Field | Change |
---|---|---|---|
2011-05-12 17:45 | 2useven10 | New Issue | |
2011-05-12 19:58 | 2useven10 | Note Added: 0006882 | |
2011-05-12 19:59 | 2useven10 | Note Edited: 0006882 | |
2011-05-12 20:34 | max rusov | Note Added: 0006883 | |
2011-05-12 21:18 | 2useven10 | Note Added: 0006884 | |
2011-05-12 22:29 | max rusov | Note Added: 0006886 | |
2011-05-13 12:45 | 2useven10 | Note Added: 0006887 | |
2011-05-13 12:46 | 2useven10 | Note Edited: 0006887 | |
2011-05-18 07:53 | 2useven10 | File Added: viewer-diff-8.7z | |
2011-05-18 07:55 | 2useven10 | Note Added: 0006890 | |
2011-05-18 14:51 | vskirdin | Note Added: 0006893 | |
2011-05-18 16:07 | vskirdin | Note Added: 0006894 | |
2011-05-18 16:22 | 2useven10 | Note Added: 0006895 | |
2011-05-18 16:30 | 2useven10 | Note Edited: 0006895 | |
2011-05-18 16:31 | 2useven10 | Note Edited: 0006895 | |
2011-05-18 20:52 | vskirdin | Note Added: 0006896 | |
2011-05-18 21:27 | 2useven10 | Note Added: 0006897 | |
2011-05-20 19:11 | 2useven10 | Note Edited: 0006897 | |
2011-05-23 14:29 | 2useven10 | Note Edited: 0006897 | |
2011-05-25 12:24 | vskirdin | Note Added: 0007033 | |
2011-05-25 13:43 | 2useven10 | Note Added: 0007038 | |
2011-05-25 13:58 | 2useven10 | Note Edited: 0007038 | |
2011-05-26 11:10 | 2useven10 | File Added: NewViewer.diff | |
2011-05-26 11:10 | 2useven10 | Note Added: 0007063 | |
2011-05-26 11:59 | vskirdin | Note Added: 0007065 | |
2011-05-26 11:59 | vskirdin | Assigned To | => vskirdin |
2011-05-26 11:59 | vskirdin | Status | new => assigned |
2011-05-26 14:04 | 2useven10 | File Added: NewViewer2.diff | |
2011-05-26 14:05 | 2useven10 | Note Added: 0007067 | |
2011-05-26 14:13 | 2useven10 | File Added: NewViewer3.diff | |
2011-05-26 14:13 | 2useven10 | Note Edited: 0007067 | |
2011-05-26 14:18 | vskirdin | Note Added: 0007069 | |
2011-05-26 14:21 | vskirdin | Note Added: 0007070 | |
2011-05-26 14:24 | vskirdin | Note Added: 0007072 | |
2011-05-26 14:43 | 2useven10 | Note Added: 0007074 | |
2011-05-26 15:11 | vskirdin | Note Added: 0007075 | |
2011-05-26 15:29 | 2useven10 | Note Added: 0007076 | |
2011-05-26 15:50 | vskirdin | Note Added: 0007077 | |
2011-05-26 15:50 | vskirdin | Status | assigned => feedback |
2011-05-27 06:46 | DrKnS | Note Added: 0007083 | |
2011-05-27 07:36 | 2useven10 | Note Added: 0007086 | |
2011-05-27 07:36 | 2useven10 | Status | feedback => assigned |
2011-06-01 11:25 | 2useven10 | File Added: ViewerLongLineFix.diff | |
2011-06-01 11:27 | 2useven10 | Note Added: 0007116 | |
2011-06-03 06:16 | vskirdin | Note Added: 0007121 | |
2011-06-03 06:16 | vskirdin | Status | assigned => feedback |
2011-06-28 14:47 | 2useven10 | File Added: NewViewer-fix2.diff | |
2011-06-28 14:50 | 2useven10 | Note Added: 0007219 | |
2011-06-28 14:50 | 2useven10 | Status | feedback => assigned |
2011-06-28 20:11 | DrKnS | Note Added: 0007220 | |
2011-06-28 20:11 | DrKnS | Status | assigned => feedback |
2011-08-11 20:34 | 2useven10 | File Added: ViewerAutoscrollAgain.diff | |
2011-08-11 20:37 | 2useven10 | Note Added: 0007441 | |
2011-08-11 20:37 | 2useven10 | Status | feedback => assigned |
2011-08-12 06:33 | vskirdin | Note Added: 0007443 | |
2011-08-12 06:33 | vskirdin | Status | assigned => feedback |
2011-08-26 06:29 | DrKnS | Note Added: 0007539 | |
2011-08-26 08:18 | 2useven10 | Note Added: 0007542 | |
2011-08-26 08:18 | 2useven10 | Status | feedback => assigned |
2011-08-26 08:31 | max rusov | Note Added: 0007543 | |
2011-08-26 08:34 | DrKnS | Note Added: 0007544 | |
2011-08-26 08:37 | 2useven10 | Note Added: 0007545 | |
2011-08-26 08:39 | DrKnS | Note Added: 0007546 | |
2011-08-26 08:44 | 2useven10 | Note Added: 0007547 | |
2011-08-26 20:26 | 2useven10 | File Added: AutoscrollOptimize.diff | |
2011-08-26 20:29 | 2useven10 | Note Added: 0007553 | |
2011-08-27 05:46 | 2useven10 | Note Edited: 0007553 | |
2011-08-28 12:27 | vskirdin | Note Added: 0007559 | |
2011-08-28 12:27 | vskirdin | Status | assigned => feedback |
2011-09-02 14:24 | samlyukov | Note Added: 0007604 | |
2011-09-02 14:25 | samlyukov | Note Edited: 0007604 | |
2011-09-02 20:03 | 2useven10 | File Added: AdjustFilePos.diff | |
2011-09-02 20:04 | 2useven10 | Note Added: 0007606 | |
2011-09-02 20:04 | 2useven10 | Status | feedback => assigned |
2011-09-10 07:54 | samlyukov | Note Added: 0007632 | |
2011-09-12 06:49 | vskirdin | Note Added: 0007653 | |
2011-09-12 06:49 | vskirdin | Status | assigned => feedback |
2011-09-26 20:33 | 2useven10 | File Added: AdjustFilePos2.diff | |
2011-09-26 20:37 | 2useven10 | Note Added: 0007749 | |
2011-09-26 20:37 | 2useven10 | Status | feedback => assigned |
2011-09-26 20:44 | 2useven10 | Note Edited: 0007749 | |
2011-09-29 06:53 | vskirdin | Note Added: 0007755 | |
2011-09-29 06:53 | vskirdin | Status | assigned => feedback |
2011-10-04 04:53 | 2useven10 | File Added: AdjustFilePos3.diff | |
2011-10-04 04:57 | 2useven10 | Note Added: 0007822 | |
2011-10-04 04:57 | 2useven10 | Status | feedback => assigned |
2011-10-04 07:11 | vskirdin | Note Added: 0007824 | |
2011-10-04 07:11 | vskirdin | Status | assigned => feedback |
2011-10-05 17:38 | 2useven10 | Note Added: 0007830 | |
2011-10-05 17:38 | 2useven10 | Status | feedback => assigned |
2011-10-07 14:20 | 2useven10 | Note Added: 0007842 | |
2011-10-07 14:27 | DrKnS | Note Added: 0007843 | |
2011-10-07 14:35 | Denis | Note Added: 0007844 | |
2011-10-07 14:35 | Denis | Note Edited: 0007844 | |
2011-10-08 09:21 | samlyukov | Note Added: 0007845 | |
2011-10-08 11:19 | 2useven10 | Note Added: 0007846 | |
2011-10-08 11:20 | 2useven10 | Note Edited: 0007846 | |
2011-10-08 22:48 | max rusov | Note Added: 0007850 | |
2011-10-10 22:21 | 2useven10 | File Added: WWrap.diff | |
2011-10-10 22:24 | 2useven10 | Note Added: 0007860 | |
2011-10-11 10:57 | vskirdin | Note Added: 0007861 | |
2011-10-11 10:57 | vskirdin | Assigned To | vskirdin => 2useven10 |
2011-10-11 11:00 | vskirdin | Note Edited: 0007861 | |
2011-10-11 11:17 | 2useven10 | Note Added: 0007862 | |
2011-10-11 11:18 | 2useven10 | Status | assigned => feedback |
2011-10-11 11:18 | 2useven10 | Status | feedback => resolved |
2011-10-11 11:20 | 2useven10 | Build | => 2217 |
2011-10-11 11:20 | 2useven10 | Status | resolved => closed |
2011-10-11 11:20 | 2useven10 | Resolution | open => fixed |
2011-10-11 11:20 | 2useven10 | Fixed in Version | => 3.0 |