View Issue Details

IDProjectCategoryView StatusLast Update
0001836WishesViewerpublic2013-07-05 14:21
Reporter2useven10 Assigned To2useven10  
PrioritylowSeverityfeatureReproducibilityN/A
Status closedResolutionsuspended 
Product Version3.0 
Summary0001836: "Виртуальный" вьювер
DescriptionПредлагаю 'на попробовать' версию вьювера, которая работает с 'виртуальнвми' файлами. Без глобализма (не COM, не VFS, не IStorage) - виртуализировано только то, что нужно для работы вьювера. Виртуальный интерфейс VFile описан в файле vFile.hpp (вместе с 2-мя имплементациями: для 'нормальных' файлов и 'файлов' в буфере). У вьювера добавлен новый public метод SetVFile(). Можно добавлять несколько раз (сейчас до 20). При открытии файла вьювером сначала проверяются все
добавленные интерфейсы в порядке обратном добавлению. Если метод NameSupported()
возвращает true - интерфейс используется при отображении 'файла', иначе стандартная работа с файлом.
Additional Informationhttp://forum.farmanager.com/viewtopic.php?f=6&t=6339

PS: я совсем не уверен, что предложенных изменений достаточно для того чтобы этой фbчей можно было пользоваться... Ни одного плагина (и даже макроса) для фар я не писал. Так что если что не так - дайте знать.
TagsNo tags attached.
Build0

Activities

2useven10

2011-07-20 12:02

developer  

Virtual_Viewer.diff (29,237 bytes)   
Index: filestr.cpp
===================================================================
--- filestr.cpp	(revision 6469)
+++ filestr.cpp	(working copy)
@@ -40,6 +40,7 @@
 #include "config.hpp"
 #include "configdb.hpp"
 #include "codepage.hpp"
+#include "vFile.hpp"
 
 const size_t DELTA = 1024;
 const size_t ReadBufCount = 0x2000;
@@ -907,34 +908,40 @@
 
 bool GetFileFormat(File& file, UINT& nCodePage, bool* pSignatureFound, bool bUseHeuristics)
 {
+	RegularFile vf(file);
+	return GetFileFormat(&vf, nCodePage, pSignatureFound, bUseHeuristics);
+}
+
+bool GetFileFormat(VFile *vf, UINT& nCodePage, bool* pSignatureFound, bool bUseHeuristics)
+{
 	DWORD dwTemp=0;
 	bool bSignatureFound = false;
 	bool bDetect=false;
 
 	DWORD Readed = 0;
-	if (file.Read(&dwTemp, sizeof(dwTemp), Readed) && Readed > 1 ) // minimum signature size is 2 bytes
+	if (vf->Read(&dwTemp, sizeof(dwTemp), Readed) && Readed > 1 ) // minimum signature size is 2 bytes
 	{
 		if (LOWORD(dwTemp) == SIGN_UNICODE)
 		{
 			nCodePage = CP_UNICODE;
-			file.SetPointer(2, nullptr, FILE_BEGIN);
+			vf->SetPointer(2, nullptr, FILE_BEGIN);
 			bSignatureFound = true;
 		}
 		else if (LOWORD(dwTemp) == SIGN_REVERSEBOM)
 		{
 			nCodePage = CP_REVERSEBOM;
-			file.SetPointer(2, nullptr, FILE_BEGIN);
+			vf->SetPointer(2, nullptr, FILE_BEGIN);
 			bSignatureFound = true;
 		}
 		else if ((dwTemp & 0x00FFFFFF) == SIGN_UTF8)
 		{
 			nCodePage = CP_UTF8;
-			file.SetPointer(3, nullptr, FILE_BEGIN);
+			vf->SetPointer(3, nullptr, FILE_BEGIN);
 			bSignatureFound = true;
 		}
 		else
 		{
-			file.SetPointer(0, nullptr, FILE_BEGIN);
+			vf->SetPointer(0, nullptr, FILE_BEGIN);
 		}
 	}
 
@@ -944,12 +951,12 @@
 	}
 	else if (bUseHeuristics)
 	{
-		file.SetPointer(0, nullptr, FILE_BEGIN);
+		vf->SetPointer(0, nullptr, FILE_BEGIN);
 		DWORD Size=0x8000; // BUGBUG. TODO: configurable
 		LPVOID Buffer=xf_malloc(Size);
 		DWORD ReadSize = 0;
-		bool ReadResult = file.Read(Buffer, Size, ReadSize);
-		file.SetPointer(0, nullptr, FILE_BEGIN);
+		bool ReadResult = vf->Read(Buffer, Size, ReadSize);
+		vf->SetPointer(0, nullptr, FILE_BEGIN);
 
 		if (ReadResult && ReadSize)
 		{
Index: cache.hpp
===================================================================
--- cache.hpp	(revision 6469)
+++ cache.hpp	(working copy)
@@ -32,12 +32,14 @@
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+class VFile;
+
 class CachedRead
 {
 public:
 	CachedRead(File& file, DWORD buffer_size=0);
 	~CachedRead();
-	bool AdjustAlignment(); // file have to be opened already
+	bool AdjustAlignment(VFile *vf=nullptr); // file have to be opened already
 	bool Read(LPVOID Data, DWORD DataSize, LPDWORD BytesRead);
 	bool FillBuffer();
 	bool Unread(DWORD BytesUnread);
@@ -52,6 +54,7 @@
 	INT64 LastPtr;
 	DWORD BufferSize; // = 2*k*Alignment (k >= 2)
 	int   Alignment;  //
+	VFile *vFile;
 };
 
 
@@ -69,5 +72,4 @@
 	enum {BufferSize=0x10000};
 	DWORD FreeSize;
 	bool Flushed;
-
 };
Index: vFile.hpp
===================================================================
--- vFile.hpp	(revision 0)
+++ vFile.hpp	(revision 0)
@@ -0,0 +1,151 @@
+#pragma once
+
+#include "farwinapi.hpp"
+
+class VFile
+{
+public:
+	virtual ~VFile() {}
+
+	enum VFile_Versions
+	{ VFile_Version_Base    = 0x100 // 1.00
+	, VFile_Version_Current = 0x100
+	};
+	virtual int Version() =0;
+	virtual bool NameSupported( const wchar_t * fname ) =0;
+
+	virtual bool Opened() =0;
+	virtual bool Open( const wchar_t *fname, bool rw=false, bool new_rw=false ) =0;
+	virtual bool Close() =0;
+	virtual bool GetFullName( string &full_name ) =0;
+
+	virtual bool SetPointer( INT64 off, PINT64 ppos, int whence ) =0;
+	virtual INT64 GetPointer() =0;
+	virtual bool Eof() =0;
+
+	virtual bool GetSize( INT64 *fsize ) =0;
+	virtual bool GetUpdateTime( FILETIME *ftime ) =0;
+	virtual int UpdateCheckPeriod() =0;
+
+	virtual bool Read( void *buff, DWORD nb, DWORD& nr ) =0;
+	virtual bool Write( void *buff, DWORD nb, DWORD& nw ) =0;
+};
+
+class RegularFile : public VFile
+{
+private:
+	File&  _file;
+	string _fnam;
+	int  _ucheck;
+
+public:
+	RegularFile(File &file, int ucheck = -1) : _file(file), _ucheck(ucheck) {}
+	~RegularFile() {}
+
+	virtual int Version() { return VFile_Version_Current; }
+	virtual bool NameSupported( const wchar_t * ) { return true; } 
+
+	virtual bool Opened() { return _file.Opened(); }
+
+	virtual bool Open( const wchar_t *fname, bool rw, bool new_rw ) {
+		_fnam = fname;
+		return _file.Open(fname,
+			rw ? GENERIC_WRITE : FILE_READ_DATA,
+			rw ? FILE_SHARE_READ : FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+			nullptr,
+			rw ? (new_rw ? CREATE_NEW : TRUNCATE_EXISTING) : OPEN_EXISTING,
+			rw ? FILE_ATTRIBUTE_ARCHIVE | FILE_FLAG_SEQUENTIAL_SCAN : 0
+		);
+	}
+
+	virtual bool Close() { return _file.Close(); }
+
+	virtual bool GetFullName( string &full_name ) {
+		full_name.Clear();
+		if ( !_fnam.IsEmpty() )
+			ConvertNameToFull( _fnam.CPtr(), full_name );
+		return !full_name.IsEmpty();
+   }
+
+	virtual bool SetPointer( INT64 off, PINT64 ppos, int whence ) { return _file.SetPointer(off,ppos,(DWORD)whence);}
+	virtual INT64 GetPointer() { return _file.GetPointer(); }
+	virtual bool Eof() { return _file.Eof(); } 
+
+	virtual bool GetSize( INT64 *fsize ) { UINT64 usz=0; bool r = _file.GetSize(usz); *fsize=(UINT64)usz; return r; }
+	virtual bool GetUpdateTime( FILETIME *ftime ) { return _file.GetTime(nullptr, nullptr, ftime, nullptr); }
+	virtual int UpdateCheckPeriod() { return _ucheck; }
+
+	virtual bool Read( void *buff, DWORD nb, DWORD& nr ) { return _file.Read( buff, nb, nr, nullptr); }
+	virtual bool Write( void *buff, DWORD nb, DWORD& nw ) { return _file.Write( buff, nb, nw, nullptr); }
+};	
+
+class BufferFile : public VFile
+{
+private:
+	const void *_data;
+	size_t      _size;
+	FILETIME _updtime;
+	string     _fname;
+	INT64        _ptr;
+
+public:
+	BufferFile(const void *data, size_t nb, const wchar_t *fn, FILETIME *ft=nullptr) { assign(data, nb, fn, ft); }
+	~BufferFile() {}
+	
+	void assign(const void *data, size_t nb, const wchar_t *fname=nullptr, FILETIME *ftime=nullptr) {
+		_data = data;
+		_size = nb;
+		if ( fname)
+			_fname = fname;
+		if ( ftime )
+			_updtime = *ftime;
+		else
+			GetSystemTimeAsFileTime(&_updtime);
+		_ptr = 0;
+	}
+
+	virtual int  Version() { return VFile_Version_Current; }
+	virtual bool NameSupported( const wchar_t *name ) { return 0 == lstrcmpW(name, _fname.CPtr()); } 
+
+	virtual bool Opened() { return true; }
+	virtual bool Open( const wchar_t *, bool rw, bool ) { return !rw; }
+	virtual bool Close() { return false; }
+
+	virtual bool GetFullName( string &full_name ) { full_name = _fname; return true; } //??? 
+
+	virtual bool SetPointer( INT64 off, PINT64 ppos, int whence ) {
+		bool ok = true;
+		if ( whence == FILE_BEGIN ) _ptr = off;
+		else if ( whence == FILE_CURRENT ) _ptr += off;
+		else if ( whence == FILE_END ) _ptr = _size + off;
+		else ok = false;
+		if ( _ptr < 0 )
+		{ _ptr = 0; ok = false; }
+		if ( ppos )
+			*ppos = _ptr;
+		return ok;
+	}
+	virtual INT64 GetPointer() { return _ptr; }
+	virtual bool  Eof() { return _ptr >= (INT64)_size; } 
+
+	virtual bool GetSize( INT64 *fsize ) { *fsize = _size; return true; }
+	virtual bool GetUpdateTime( FILETIME *ftime ) { *ftime = _updtime; return true; }
+	virtual int  UpdateCheckPeriod() { return +1; }
+
+	virtual bool Read( void *buff, DWORD nb, DWORD& nr )
+	{
+		if ( !buff )
+			return false;
+		if ( _ptr >= (INT64)_size )
+			nb = 0;
+		else if ( _ptr + nb > (INT64)_size )
+			nb = (DWORD)(_size - _ptr);
+		if ( (nr = nb) > 0 ) {
+			memmove(buff, (const char *)_data+(size_t)_ptr, nb);
+			_ptr += nb;
+		}
+		return true;
+	}
+
+	virtual bool Write( void *, DWORD, DWORD& ) { return false; } //...
+};	
Index: viewer.hpp
===================================================================
--- viewer.hpp	(revision 6469)
+++ viewer.hpp	(working copy)
@@ -38,6 +38,7 @@
 #include "plugin.hpp"
 #include "poscache.hpp"
 #include "config.hpp"
+#include "vFile.hpp"
 #include "cache.hpp"
 
 #define MAXSCRY       512                    // 300   // 120
@@ -174,6 +175,10 @@
 		int  vgetc_ib;
 		wchar_t vgetc_composite;
 
+		VFile *vFile;
+		VFile *vFiles[20];
+		int nvFiles;
+
 	private:
 		virtual void DisplayObject();
 
@@ -220,6 +225,12 @@
 		bool veof();
 		wchar_t vgetc_prev();
 
+		bool vOpened();
+		bool vClose();
+		bool vOpen( const wchar_t *fname );
+
+		bool vGetFileFormat(UINT& cp, bool bHeuristic);
+
 		void SetFileSize();
 		int GetStrBytesNum(const wchar_t *Str, int Length);
 
@@ -297,4 +308,6 @@
 		int ProcessTypeWrapMode(int newMode, bool isRedraw=TRUE);
 
 		void SearchTextTransform(UnicodeString &to, const wchar_t *from, bool hex2text, int &pos);
+
+		bool SetVFile( VFile *vf, bool add=true );
 };
Index: cache.cpp
===================================================================
--- cache.cpp	(revision 6469)
+++ cache.cpp	(working copy)
@@ -34,17 +34,18 @@
 #pragma hdrstop
 
 #include "cache.hpp"
+#include "vFile.hpp"
 
 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));
+	vFile = nullptr;
 }
 
 CachedRead::~CachedRead()
@@ -52,15 +53,17 @@
 	xf_free(Buffer);
 }
 
-bool CachedRead::AdjustAlignment()
+bool CachedRead::AdjustAlignment( VFile *vf )
 {
-	if (!file.Opened())
+	vFile = vf;
+
+	if ( (vFile && !vFile->Opened()) || (!vFile && !file.Opened()) )
 		return false;
 
 	DWORD ret, buff_size = BufferSize;
 	DISK_GEOMETRY g;
 
-	if (file.IoControl(IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr,0, &g,(DWORD)sizeof(g), &ret,nullptr))
+	if (!vFile && file.IoControl(IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr,0, &g,(DWORD)sizeof(g), &ret,nullptr))
 	{
 		if (g.BytesPerSector > 512 && g.BytesPerSector <= 256*1024)
 		{
@@ -90,7 +93,7 @@
 
 bool CachedRead::Read(LPVOID Data, DWORD DataSize, LPDWORD BytesRead)
 {
-	INT64 Ptr = file.GetPointer();
+	INT64 Ptr = vFile ? vFile->GetPointer() : file.GetPointer();
 
 	if(Ptr!=LastPtr)
 	{
@@ -121,18 +124,22 @@
 
 			Result=true;
 
-			DWORD Actual=Min(BytesLeft, DataSize);
+			DWORD Actual = Min(BytesLeft, DataSize);
 			memcpy(Data, &Buffer[ReadSize-BytesLeft], Actual);
-			Data=((LPBYTE)Data)+Actual;
-			BytesLeft-=Actual;
-			file.SetPointer(Actual, &LastPtr, FILE_CURRENT);
-			*BytesRead+=Actual;
-			DataSize-=Actual;
+			Data = ((LPBYTE)Data)+Actual;
+			BytesLeft -= Actual;
+			if ( vFile )
+				vFile->SetPointer(Actual, &LastPtr, FILE_CURRENT);
+			else
+				file.SetPointer(Actual, &LastPtr, FILE_CURRENT);
+
+			*BytesRead += Actual;
+			DataSize -= Actual;
 		}
 	}
 	else
 	{
-		Result = file.Read(Data, DataSize, *BytesRead);
+		Result = vFile ? vFile->Read(Data, DataSize, *BytesRead) : file.Read(Data, DataSize, *BytesRead);
 	}
 	return Result;
 }
@@ -143,7 +150,10 @@
 	{
 		BytesLeft += BytesUnread;
 		__int64 off = BytesUnread;
-		file.SetPointer(-off, &LastPtr, FILE_CURRENT);
+		if ( vFile)
+			vFile->SetPointer(-off, &LastPtr, FILE_CURRENT);
+		else
+			file.SetPointer(-off, &LastPtr, FILE_CURRENT);
 		return true;
 	}
 	return false;
@@ -152,29 +162,39 @@
 bool CachedRead::FillBuffer()
 {
 	bool Result=false;
-	if (!file.Eof())
+	if ( (vFile && !vFile->Eof()) || (!vFile && !file.Eof()) )
 	{
-		INT64 Pointer = file.GetPointer();
+		INT64 Pointer = vFile ? vFile->GetPointer() : file.GetPointer();
 
 		int shift = (int)(Pointer % Alignment);
 		if (Pointer-shift > BufferSize/2)
 			shift += BufferSize/2;
 
-		if (shift)
-			file.SetPointer(-shift, nullptr, FILE_CURRENT);
+		if ( shift ) {
+			if ( vFile )
+				vFile->SetPointer(-shift, nullptr, FILE_CURRENT);
+			else
+				file.SetPointer(-shift, nullptr, FILE_CURRENT);
+		}
 
 		DWORD read_size = BufferSize;
-		UINT64 FileSize = 0;
-		if (file.GetSize(FileSize) && Pointer-shift+BufferSize > (INT64)FileSize)
-			read_size = (DWORD)((INT64)FileSize-Pointer+shift);
+		union { UINT64 u64FileSize; INT64 i64FileSize; } u;
+		u.i64FileSize = 0;
+		bool ok_size = vFile ? vFile->GetSize(&u.i64FileSize) : file.GetSize(u.u64FileSize);
 
-		Result = file.Read(Buffer, read_size, ReadSize);
+		if (ok_size && Pointer-shift+BufferSize > u.i64FileSize)
+			read_size = (DWORD)(u.i64FileSize-Pointer+shift);
+
+		Result = vFile ? vFile->Read(Buffer, read_size, ReadSize) : file.Read(Buffer, read_size, ReadSize);
 		if (Result)
 		{
 			if (ReadSize > (DWORD)shift)
 			{
 				BytesLeft = ReadSize - shift;
-				file.SetPointer(Pointer, nullptr, FILE_BEGIN);
+				if ( vFile )
+					vFile->SetPointer(Pointer, nullptr, FILE_BEGIN);
+				else
+					file.SetPointer(Pointer, nullptr, FILE_BEGIN);
 			}
 			else
 			{
@@ -183,8 +203,12 @@
 		}
 		else
 		{
-			if (shift)
-				file.SetPointer(Pointer, nullptr, FILE_BEGIN);
+			if (shift) {
+				if ( vFile )
+					vFile->SetPointer(Pointer, nullptr, FILE_BEGIN);
+				else
+					file.SetPointer(Pointer, nullptr, FILE_BEGIN);
+			}
 			ReadSize=0;
 			BytesLeft=0;
 		}
@@ -214,13 +238,13 @@
 bool CachedWrite::Write(LPCVOID Data, DWORD DataSize)
 {
 	bool Result=false;
-	bool SuccessFlush=true;
+	bool SuccessFlush = true;
 
-	if (Buffer)
+	if ( Buffer )
 	{
 		if (DataSize>FreeSize)
 		{
-			SuccessFlush=Flush();
+			SuccessFlush = Flush();
 		}
 
 		if(SuccessFlush)
@@ -228,8 +252,9 @@
 			if (DataSize>FreeSize)
 			{
 				DWORD WrittenSize=0;
+				bool ok_wr = file.Write(Data,DataSize,WrittenSize);
 
-				if (file.Write(Data, DataSize,WrittenSize) && DataSize==WrittenSize)
+				if (ok_wr && DataSize==WrittenSize)
 				{
 					Result=true;
 				}
@@ -253,8 +278,9 @@
 		if (!Flushed)
 		{
 			DWORD WrittenSize=0;
+			bool ok_wr = file.Write(Buffer,BufferSize-FreeSize,WrittenSize);
 
-			if (file.Write(Buffer, BufferSize-FreeSize, WrittenSize, nullptr) && BufferSize-FreeSize==WrittenSize)
+			if (ok_wr && BufferSize-FreeSize==WrittenSize)
 			{
 				Flushed=true;
 				FreeSize=BufferSize;
Index: filestr.hpp
===================================================================
--- filestr.hpp	(revision 6469)
+++ filestr.hpp	(working copy)
@@ -105,4 +105,7 @@
 		int GetUnicodeString(LPWSTR* DestStr, int& Length, bool bBigEndian);
 };
 
-bool GetFileFormat(File& file, UINT& nCodePage, bool* pSignatureFound = nullptr, bool bUseHeuristics = true);
\ No newline at end of file
+bool GetFileFormat(File& file, UINT& nCodePage, bool* pSignatureFound = nullptr, bool bUseHeuristics = true);
+
+class VFile;
+bool GetFileFormat(VFile *vf, UINT& nCodePage, bool* pSignatureFound = nullptr, bool bUseHeuristics = true);
Index: viewer.cpp
===================================================================
--- viewer.cpp	(revision 6469)
+++ viewer.cpp	(working copy)
@@ -158,16 +158,86 @@
 
 	memset(&vString, 0, sizeof(vString));
 	vString.lpData = new wchar_t[MAX_VIEWLINEB];
+
+	vFile = nullptr;
+	SetVFile(nullptr, false);
 }
 
+bool Viewer::SetVFile( VFile *vf, bool add )
+{
+	if ( !vf )
+	{
+		if ( add )
+			return false;
+		for ( size_t i = 0; i < ARRAYSIZE(vFiles); ++i )
+			vFiles[i] = nullptr;
+		nvFiles = 0;
+		return true;
+	}
 
+	// remove previous one if exists
+   //
+	for ( int i = 0; i < nvFiles; ++i ) {
+		if ( vFiles[i] == vf ) {
+			if ( i < nvFiles-1 )
+				memmove(vFiles+i, vFiles+i+1, nvFiles-i-1);
+			--nvFiles;
+			if ( add )
+				break;
+			else
+				return true; // successfully deleted
+		}
+	}
+	if ( !add )
+		return false; // delete not success
+
+	if ( nvFiles >= (int)ARRAYSIZE(vFiles) )
+		return false; // too many
+
+	vFiles[nvFiles++] = vf; // add new
+	return true;
+}
+
+bool Viewer::vOpened()
+{
+	if ( vFile )
+		return vFile->Opened();
+	else
+		return ViewFile.Opened();
+}
+
+bool Viewer::vClose()
+{
+	if ( vFile )
+		return vFile->Close();
+	else
+		return ViewFile.Close();
+}
+
+bool Viewer::vOpen( const wchar_t *fname )
+{
+	if ( vFile )
+		return vFile->Open( fname );
+	else
+		return ViewFile.Open(fname, FILE_READ_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, nullptr, OPEN_EXISTING);
+}
+
+bool Viewer::vGetFileFormat(UINT& cp, bool bHeuristic)
+{
+	bool detect = vFile
+		? GetFileFormat(vFile, cp, &Signature, bHeuristic)
+		: GetFileFormat(ViewFile, cp, &Signature, bHeuristic
+	);
+	return detect;
+}
+
 Viewer::~Viewer()
 {
 	KeepInitParameters();
 
-	if (ViewFile.Opened())
+	if (vOpened())
 	{
-		ViewFile.Close();
+		vClose();
 
 		if (Opt.ViOpt.SavePos)
 		{
@@ -245,21 +315,51 @@
 	//InitHex=VM.Hex;
 }
 
+static bool IsDriveTypeFLOPPY( const string &strRoot ) // media have to be inserted...
+{
+	bool floppy = true; // returns true if can't open drive
 
+	string drive = HasPathPrefix(strRoot) ? strRoot : L"\\\\?\\" + strRoot;
+	DeleteEndSlash(drive, false);
+
+	HANDLE hDevice = ::CreateFileW(
+		drive.CPtr(),
+		GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, 0, nullptr
+	);
+	if ( INVALID_HANDLE_VALUE != hDevice )
+	{
+		DISK_GEOMETRY g;
+		DWORD dwOutBytes;
+		if ( DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL,0, &g,(DWORD)sizeof(g), &dwOutBytes,NULL)	)
+			floppy = ( g.MediaType != FixedMedia && g.MediaType != RemovableMedia );
+		CloseHandle(hDevice);
+	}
+	return floppy;
+}
+
 int Viewer::OpenFile(const wchar_t *Name,int warning)
 {
 	VM.CodePage=DefCodePage;
 	DefCodePage=CP_AUTODETECT;
 	OpenFailed=false;
 
-	ViewFile.Close();
+	vClose();
+
+	vFile = nullptr;
+	for ( int j = nvFiles-1; j >= 0; --j )	{ // looks for appropriate virtual file (latest first)
+		if ( vFiles[j]->NameSupported(Name) ) {
+			vFile = vFiles[j];
+			break;
+		}
+	}
+
 	Reader.Clear();
 	vgetc_ready = lcache_ready = false;
 
 	SelectSize = -1; // ������� ��������
 	strFileName = Name;
 
-	if (Opt.OnlyEditorViewerUsed && !StrCmp(strFileName, L"-"))
+	if (!vFile && Opt.OnlyEditorViewerUsed && !StrCmp(strFileName, L"-"))
 	{
 		string strTempName;
 
@@ -290,10 +390,10 @@
 	}
 	else
 	{
-		ViewFile.Open(strFileName, FILE_READ_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, nullptr, OPEN_EXISTING);
+		vOpen(strFileName.CPtr());
 	}
 
-	if (!ViewFile.Opened())
+	if (!vOpened())
 	{
 		/* $ 04.07.2000 tran
 		   + 'warning' flag processing, in QuickView it is FALSE
@@ -305,12 +405,21 @@
 		OpenFailed=true;
 		return FALSE;
 	}
-	Reader.AdjustAlignment();
+	Reader.AdjustAlignment(vFile);
 
 	CodePageChangedByUser=FALSE;
 
-	ConvertNameToFull(strFileName,strFullFileName);
-	apiGetFindDataEx(strFileName, ViewFindData);
+	if ( vFile )
+	{
+		vFile->GetFullName(strFullFileName);
+		vFile->GetSize((PINT64)&ViewFindData.nFileSize);
+		vFile->GetUpdateTime(&ViewFindData.ftLastWriteTime);
+	}
+	else
+	{
+		ConvertNameToFull(strFileName,strFullFileName);
+		apiGetFindDataEx(strFileName, ViewFindData);
+	}
 	UINT CachedCodePage=0;
 
 	if (Opt.ViOpt.SavePos && !ReadStdin)
@@ -349,7 +458,7 @@
 
 		if (VM.CodePage == CP_AUTODETECT || IsUnicodeOrUtfCodePage(VM.CodePage))
 		{
-			Detect=GetFileFormat(ViewFile,CodePage,&Signature,Opt.ViOpt.AutoDetectCodePage!=0);
+			Detect = vGetFileFormat(CodePage, Opt.ViOpt.AutoDetectCodePage != 0);
 
 			// �������� ������������� ��� ��� ���������������� ������ �������
 			if (Detect)
@@ -377,7 +486,7 @@
 			CodePageChangedByUser=TRUE;
 		}
 
-		ViewFile.SetPointer(0, nullptr, FILE_BEGIN);
+		vseek(0, FILE_BEGIN);
 	}
 	SetFileSize();
 
@@ -393,19 +502,23 @@
 	bVE_READ_Sent = true;
 
 	last_update_check = GetTickCount();
-	string strRoot;
-	GetPathRoot(strFullFileName, strRoot);
-	int DriveType = FAR_GetDriveType(strRoot);
-	if (IsDriveTypeCDROM(DriveType))
-		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: 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
+	if ( vFile )
+		update_check_period = vFile->UpdateCheckPeriod();
+	else {
+		string strRoot;
+		GetPathRoot(strFullFileName, strRoot);
+		int DriveType = FAR_GetDriveType(strRoot);
+		if (IsDriveTypeCDROM(DriveType))
+			DriveType = DRIVE_CDROM;
+		switch (DriveType)
+		{                                                    // floppy: never, flash drive: 0.5 sec
+			case DRIVE_REMOVABLE: update_check_period = IsDriveTypeFLOPPY(strRoot) ? -1 : 500; break;
+			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;
@@ -431,7 +544,7 @@
 	int I,Y;
 	AdjustWidth();
 
-	if (!ViewFile.Opened())
+	if (!vOpened())
 	{
 		if (!strFileName.IsEmpty() && ((nMode == SHOW_RELOAD) || (nMode == SHOW_HEX)))
 		{
@@ -1128,9 +1241,9 @@
 		case MCODE_C_SELECTED:
 			return (__int64)(SelectSize >= 0 ?TRUE:FALSE);
 		case MCODE_C_EOF:
-			return (__int64)(LastPage || !ViewFile.Opened());
+			return (__int64)(LastPage || !vOpened());
 		case MCODE_C_BOF:
-			return (__int64)(!FilePos || !ViewFile.Opened());
+			return (__int64)(!FilePos || !vOpened());
 		case MCODE_V_VIEWERSTATE:
 		{
 			DWORD MacroViewerState=0;
@@ -1218,7 +1331,7 @@
 		case KEY_CTRLC:
 		case KEY_CTRLINS:  case KEY_CTRLNUMPAD0:
 		{
-			if (SelectSize >= 0 && ViewFile.Opened())
+			if (SelectSize >= 0 && vOpened())
 			{
 				wchar_t *SelData = (wchar_t*)xf_malloc((size_t)SelectSize+1);
 				if ( SelData )
@@ -1248,7 +1361,7 @@
 		}
 		case KEY_IDLE:
 		{
-			if (ViewFile.Opened() && update_check_period >= 0)
+			if (vOpened() && update_check_period >= 0)
 			{
 				DWORD now_ticks = GetTickCount();
 				if ((int)(now_ticks - last_update_check) < update_check_period)
@@ -1256,7 +1369,11 @@
 				last_update_check = now_ticks;
 
 				FAR_FIND_DATA_EX NewViewFindData;
-				if (!apiGetFindDataEx(strFullFileName, NewViewFindData))
+				bool ok = vFile
+					? vFile->GetSize((PINT64)&NewViewFindData.nFileSize) && vFile->GetUpdateTime(&NewViewFindData.ftLastWriteTime)
+					: apiGetFindDataEx(strFullFileName, NewViewFindData) != 0
+				;
+				if ( !ok )
 					return TRUE;
 
 				if (ViewFindData.ftLastWriteTime.dwLowDateTime!=NewViewFindData.ftLastWriteTime.dwLowDateTime
@@ -1267,7 +1384,8 @@
 					SetFileSize();
 
 					Reader.Clear(); // ���� ���� �� ��� ����?
-					ViewFile.FlushBuffers();
+					if ( !vFile )
+						ViewFile.FlushBuffers();
 					vseek(0, SEEK_CUR); // reset vgetc state
 					lcache_ready = false; // reset start-lines cache
 
@@ -1424,7 +1542,7 @@
 				if (nCodePage == (CP_AUTODETECT & 0xffff))
 				{
 					__int64 fpos = vtell();
-					bool detect = GetFileFormat(ViewFile,nCodePage,&Signature,true) && IsCodePageSupported(nCodePage);
+					bool detect = vGetFileFormat(nCodePage, true) && IsCodePageSupported(nCodePage);
 					vseek(fpos, SEEK_SET);
 					if (!detect)
 						nCodePage = Opt.ViOpt.AnsiCodePageAsDefault ? GetACP() : GetOEMCP();
@@ -1440,7 +1558,7 @@
 		}
 		case KEY_ALTF8:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				LastPage = 0;
 				GoTo();
@@ -1498,7 +1616,7 @@
 		}
 		case KEY_UP: case KEY_NUMPAD8: case KEY_SHIFTNUMPAD8:
 		{
-			if (FilePos>0 && ViewFile.Opened())
+			if (FilePos>0 && vOpened())
 			{
 				Up(1);	// LastPage = 0
 
@@ -1519,7 +1637,7 @@
 		}
 		case KEY_DOWN: case KEY_NUMPAD2:  case KEY_SHIFTNUMPAD2:
 		{
-			if (!LastPage && ViewFile.Opened())
+			if (!LastPage && vOpened())
 			{
 				if (VM.Hex)
 				{
@@ -1534,7 +1652,7 @@
 		}
 		case KEY_PGUP: case KEY_NUMPAD9: case KEY_SHIFTNUMPAD9: case KEY_CTRLUP:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				Up(Y2-Y1);
 				Show();
@@ -1544,7 +1662,7 @@
 		}
 		case KEY_PGDN: case KEY_NUMPAD3:  case KEY_SHIFTNUMPAD3: case KEY_CTRLDOWN:
 		{
-			if (LastPage || !ViewFile.Opened())
+			if (LastPage || !vOpened())
 				return TRUE;
 
 			FilePos = EndOfScreen(-1); // start of last screen line
@@ -1572,7 +1690,7 @@
 		}
 		case KEY_LEFT: case KEY_NUMPAD4: case KEY_SHIFTNUMPAD4:
 		{
-			if (LeftPos>0 && ViewFile.Opened())
+			if (LeftPos>0 && vOpened())
 			{
 				if (VM.Hex && LeftPos>80-Width)
 					LeftPos=Max(80-Width,1);
@@ -1585,7 +1703,7 @@
 		}
 		case KEY_RIGHT: case KEY_NUMPAD6: case KEY_SHIFTNUMPAD6:
 		{
-			if (LeftPos<MAX_VIEWLINE && ViewFile.Opened() && !VM.Hex && !VM.Wrap)
+			if (LeftPos<MAX_VIEWLINE && vOpened() && !VM.Hex && !VM.Wrap)
 			{
 				LeftPos++;
 				Show();
@@ -1595,7 +1713,7 @@
 		}
 		case KEY_CTRLLEFT: case KEY_CTRLNUMPAD4:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				if (VM.Hex)
 				{
@@ -1613,7 +1731,7 @@
 		}
 		case KEY_CTRLRIGHT: case KEY_CTRLNUMPAD6:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				if (VM.Hex)
 				{
@@ -1635,7 +1753,7 @@
 		case KEY_CTRLSHIFTLEFT:    case KEY_CTRLSHIFTNUMPAD4:
 
 			// ������� �� ����� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				LeftPos = 0;
 				Show();
@@ -1645,7 +1763,7 @@
 		case KEY_CTRLSHIFTRIGHT:     case KEY_CTRLSHIFTNUMPAD6:
 		{
 			// ������� �� ���� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				int I, Y, Len, MaxLen = 0;
 
@@ -1671,11 +1789,11 @@
 		case KEY_HOME:        case KEY_NUMPAD7:   case KEY_SHIFTNUMPAD7:
 
 			// ������� �� ����� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 				LeftPos=0;
 
 		case KEY_CTRLPGUP:    case KEY_CTRLNUMPAD9:
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				FilePos=0;
 				Show();
@@ -1686,12 +1804,12 @@
 		case KEY_END:         case KEY_NUMPAD1: case KEY_SHIFTNUMPAD1:
 
 			// ������� �� ���� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 				LeftPos=0;
 
 		case KEY_CTRLPGDN:    case KEY_CTRLNUMPAD3:
 
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				/* $ 15.08.2002 IS
 				   �� ������ ������, ���� ������� ������ �� �������� �������
@@ -1981,7 +2099,7 @@
 {
 	assert( nlines > 0 );
 
-	if (!ViewFile.Opened())
+	if (!vOpened())
 		return;
 
 	LastPage = 0;
@@ -2996,7 +3114,7 @@
 */
 void Viewer::Search(int Next,int FirstChar)
 {
-	if (!ViewFile.Opened() || (Next && strLastSearchStr.IsEmpty()))
+	if (!vOpened() || (Next && strLastSearchStr.IsEmpty()))
 		return;
 
 	string strSearchStr, strMsgStr;
@@ -3541,12 +3659,16 @@
 	}
 
 	vgetc_ready = false;
-	return ViewFile.SetPointer(Offset, nullptr, Whence);
+
+	return vFile
+		? vFile->SetPointer(Offset, nullptr, Whence)
+		: ViewFile.SetPointer(Offset, nullptr, Whence)
+	;
 }
 
 __int64 Viewer::vtell()
 {
-	__int64 Ptr = ViewFile.GetPointer();
+	__int64 Ptr = vFile ? vFile->GetPointer() : ViewFile.GetPointer();
 
 	if (vgetc_ready)
 		Ptr -= (vgetc_cb - vgetc_ib);
@@ -3559,7 +3681,7 @@
 	if (vgetc_ready && vgetc_ib < vgetc_cb)
 		return false;
 	else
-		return ViewFile.Eof();
+		return vFile ? vFile->Eof() : ViewFile.Eof();
 }
 
 bool Viewer::vgetc(wchar_t *pCh)
@@ -3567,7 +3689,7 @@
 	if (!vgetc_ready)
 		vgetc_cb = vgetc_ib = (int)(vgetc_composite = 0);
 
-	if (vgetc_cb - vgetc_ib < 4 && !ViewFile.Eof())
+	if (vgetc_cb - vgetc_ib < 4 && !(vFile ? vFile->Eof() : ViewFile.Eof()))
 	{
 		vgetc_cb -= vgetc_ib;
 		if (vgetc_cb && vgetc_ib)
@@ -3853,12 +3975,18 @@
 
 void Viewer::SetFileSize()
 {
-	if (!ViewFile.Opened())
+	if (!vOpened())
 		return;
 
-	UINT64 uFileSize=0; // BUGBUG, sign
-	ViewFile.GetSize(uFileSize);
-	FileSize=uFileSize;
+	union { UINT64 u64FileSize; INT64 i64FileSize; } u;
+	u.i64FileSize = 0;
+
+	if ( vFile )
+		vFile->GetSize(&u.i64FileSize);
+	else
+		ViewFile.GetSize(u.u64FileSize);
+
+	FileSize = u.i64FileSize;
 }
 
 
@@ -3874,7 +4002,7 @@
 //
 void Viewer::SelectText(const __int64 &match_pos,const __int64 &search_len, const DWORD flags)
 {
-	if (!ViewFile.Opened())
+	if (!vOpened())
 		return;
 
 	SelectPos = match_pos;
Virtual_Viewer.diff (29,237 bytes)   

2useven10

2011-07-21 13:13

developer  

Virtual_Viewer1.diff (29,052 bytes)   
Index: filestr.cpp
===================================================================
--- filestr.cpp	(revision 6469)
+++ filestr.cpp	(working copy)
@@ -40,6 +40,7 @@
 #include "config.hpp"
 #include "configdb.hpp"
 #include "codepage.hpp"
+#include "vFile.hpp"
 
 const size_t DELTA = 1024;
 const size_t ReadBufCount = 0x2000;
@@ -907,34 +908,40 @@
 
 bool GetFileFormat(File& file, UINT& nCodePage, bool* pSignatureFound, bool bUseHeuristics)
 {
+	RegularFile vf(file);
+	return GetFileFormat(&vf, nCodePage, pSignatureFound, bUseHeuristics);
+}
+
+bool GetFileFormat(VFile *vf, UINT& nCodePage, bool* pSignatureFound, bool bUseHeuristics)
+{
 	DWORD dwTemp=0;
 	bool bSignatureFound = false;
 	bool bDetect=false;
 
 	DWORD Readed = 0;
-	if (file.Read(&dwTemp, sizeof(dwTemp), Readed) && Readed > 1 ) // minimum signature size is 2 bytes
+	if (vf->Read(&dwTemp, sizeof(dwTemp), Readed) && Readed > 1 ) // minimum signature size is 2 bytes
 	{
 		if (LOWORD(dwTemp) == SIGN_UNICODE)
 		{
 			nCodePage = CP_UNICODE;
-			file.SetPointer(2, nullptr, FILE_BEGIN);
+			vf->SetPointer(2, nullptr, FILE_BEGIN);
 			bSignatureFound = true;
 		}
 		else if (LOWORD(dwTemp) == SIGN_REVERSEBOM)
 		{
 			nCodePage = CP_REVERSEBOM;
-			file.SetPointer(2, nullptr, FILE_BEGIN);
+			vf->SetPointer(2, nullptr, FILE_BEGIN);
 			bSignatureFound = true;
 		}
 		else if ((dwTemp & 0x00FFFFFF) == SIGN_UTF8)
 		{
 			nCodePage = CP_UTF8;
-			file.SetPointer(3, nullptr, FILE_BEGIN);
+			vf->SetPointer(3, nullptr, FILE_BEGIN);
 			bSignatureFound = true;
 		}
 		else
 		{
-			file.SetPointer(0, nullptr, FILE_BEGIN);
+			vf->SetPointer(0, nullptr, FILE_BEGIN);
 		}
 	}
 
@@ -944,12 +951,12 @@
 	}
 	else if (bUseHeuristics)
 	{
-		file.SetPointer(0, nullptr, FILE_BEGIN);
+		vf->SetPointer(0, nullptr, FILE_BEGIN);
 		DWORD Size=0x8000; // BUGBUG. TODO: configurable
 		LPVOID Buffer=xf_malloc(Size);
 		DWORD ReadSize = 0;
-		bool ReadResult = file.Read(Buffer, Size, ReadSize);
-		file.SetPointer(0, nullptr, FILE_BEGIN);
+		bool ReadResult = vf->Read(Buffer, Size, ReadSize);
+		vf->SetPointer(0, nullptr, FILE_BEGIN);
 
 		if (ReadResult && ReadSize)
 		{
Index: plugapi.cpp
===================================================================
--- plugapi.cpp	(revision 6469)
+++ plugapi.cpp	(working copy)
@@ -1802,6 +1802,15 @@
 	if (FrameManager->ManagerIsDown())
 		return FALSE;
 
+	VFile *vf = nullptr;
+	string fname;
+	if ( 0 != (Flags & VF_VFILE) )
+	{
+		vf = (VFile *)(FileName); //!!! dirty hack
+		vf->GetName(fname);
+		FileName = fname.CPtr();
+	}
+
 	class ConsoleTitle ct;
 	int DisableHistory=(Flags & VF_DISABLEHISTORY)?TRUE:FALSE;
 
@@ -1819,6 +1828,8 @@
 		if (!Viewer)
 			return FALSE;
 
+		Viewer->SetVFile(vf);
+
 		/* $ 14.06.2002 IS
 		   ��������� VF_DELETEONLYFILEONCLOSE - ���� ���� ����� ����� ������
 		   ��������� �� �������� � VF_DELETEONCLOSE
@@ -1853,6 +1864,8 @@
 		FrameManager->ExecuteModal();
 		FrameManager->ExitModalEV();
 
+		Viewer.SetVFile(vf);
+
 		/* $ 14.06.2002 IS
 		   ��������� VF_DELETEONLYFILEONCLOSE - ���� ���� ����� ����� ������
 		   ��������� �� �������� � VF_DELETEONCLOSE
Index: cache.hpp
===================================================================
--- cache.hpp	(revision 6469)
+++ cache.hpp	(working copy)
@@ -32,12 +32,14 @@
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+class VFile;
+
 class CachedRead
 {
 public:
 	CachedRead(File& file, DWORD buffer_size=0);
 	~CachedRead();
-	bool AdjustAlignment(); // file have to be opened already
+	bool AdjustAlignment(VFile *vf=nullptr); // file have to be opened already
 	bool Read(LPVOID Data, DWORD DataSize, LPDWORD BytesRead);
 	bool FillBuffer();
 	bool Unread(DWORD BytesUnread);
@@ -52,6 +54,7 @@
 	INT64 LastPtr;
 	DWORD BufferSize; // = 2*k*Alignment (k >= 2)
 	int   Alignment;  //
+	VFile *vFile;
 };
 
 
@@ -69,5 +72,4 @@
 	enum {BufferSize=0x10000};
 	DWORD FreeSize;
 	bool Flushed;
-
 };
Index: vFile.hpp
===================================================================
--- vFile.hpp	(revision 0)
+++ vFile.hpp	(revision 0)
@@ -0,0 +1,130 @@
+#pragma once
+
+#include "farwinapi.hpp"
+
+class VFile
+{
+public:
+	virtual ~VFile() {}
+
+	enum VFile_Versions
+	{ VFile_Version_Base    = 0x100 // 1.00
+	, VFile_Version_Current = 0x100
+	};
+	virtual int Version() =0;
+
+	virtual bool GetName( string& fname, bool full=false ) =0;
+
+	virtual bool SetPointer( INT64 off, PINT64 ppos, int whence ) =0;
+	virtual INT64 GetPointer() =0;
+	virtual bool Eof() =0;
+
+	virtual bool GetSize( INT64 *fsize ) =0;
+	virtual bool GetUpdateTime( FILETIME *ftime ) =0;
+	virtual int UpdateCheckPeriod() =0;
+
+	virtual bool Read( void *buff, DWORD nb, DWORD& nr ) =0;
+	virtual bool Write( void *buff, DWORD nb, DWORD& nw ) =0;
+};
+
+class RegularFile : public VFile
+{
+private:
+	File&  _file;
+	string _fnam;
+	int  _ucheck;
+
+public:
+	RegularFile(File &file, int ucheck = -1) : _file(file), _ucheck(ucheck) {}
+	~RegularFile() {}
+
+	virtual int Version() { return VFile_Version_Current; }
+
+	virtual bool GetName( string &fname, bool full ) {
+		fname.Clear();
+		if ( !_file.Opened() )
+			return false;
+		if ( !full )
+			fname = _fnam;
+		else
+			ConvertNameToFull( _fnam.CPtr(), fname);
+		return true;
+   }
+
+	virtual bool SetPointer( INT64 off, PINT64 ppos, int whence ) { return _file.SetPointer(off,ppos,(DWORD)whence);}
+	virtual INT64 GetPointer() { return _file.GetPointer(); }
+	virtual bool Eof() { return _file.Eof(); } 
+
+	virtual bool GetSize( INT64 *fsize ) { UINT64 usz=0; bool r = _file.GetSize(usz); *fsize=(UINT64)usz; return r; }
+	virtual bool GetUpdateTime( FILETIME *ftime ) { return _file.GetTime(nullptr, nullptr, ftime, nullptr); }
+	virtual int UpdateCheckPeriod() { return _ucheck; }
+
+	virtual bool Read( void *buff, DWORD nb, DWORD& nr ) { return _file.Read( buff, nb, nr, nullptr); }
+	virtual bool Write( void *buff, DWORD nb, DWORD& nw ) { return _file.Write( buff, nb, nw, nullptr); }
+};	
+
+class BufferFile : public VFile
+{
+private:
+	const void *_data;
+	size_t      _size;
+	FILETIME _updtime;
+	string     _fname;
+	INT64        _ptr;
+
+public:
+	BufferFile(const void *data, size_t nb, const wchar_t *fn, FILETIME *ft=nullptr) { assign(data, nb, fn, ft); }
+	~BufferFile() {}
+	
+	void assign(const void *data, size_t nb, const wchar_t *fname=nullptr, FILETIME *ftime=nullptr) {
+		_data = data;
+		_size = nb;
+		if ( fname)
+			_fname = fname;
+		if ( ftime )
+			_updtime = *ftime;
+		else
+			GetSystemTimeAsFileTime(&_updtime);
+		_ptr = 0;
+	}
+
+	virtual int  Version() { return VFile_Version_Current; }
+
+	virtual bool GetName( string &fname, bool ) { fname = _fname; return true; } //??? 
+
+	virtual bool SetPointer( INT64 off, PINT64 ppos, int whence ) {
+		bool ok = true;
+		if ( whence == FILE_BEGIN ) _ptr = off;
+		else if ( whence == FILE_CURRENT ) _ptr += off;
+		else if ( whence == FILE_END ) _ptr = _size + off;
+		else ok = false;
+		if ( _ptr < 0 )
+		{ _ptr = 0; ok = false; }
+		if ( ppos )
+			*ppos = _ptr;
+		return ok;
+	}
+	virtual INT64 GetPointer() { return _ptr; }
+	virtual bool  Eof() { return _ptr >= (INT64)_size; } 
+
+	virtual bool GetSize( INT64 *fsize ) { *fsize = _size; return true; }
+	virtual bool GetUpdateTime( FILETIME *ftime ) { *ftime = _updtime; return true; }
+	virtual int  UpdateCheckPeriod() { return +1; }
+
+	virtual bool Read( void *buff, DWORD nb, DWORD& nr )
+	{
+		if ( !buff )
+			return false;
+		if ( _ptr >= (INT64)_size )
+			nb = 0;
+		else if ( _ptr + nb > (INT64)_size )
+			nb = (DWORD)(_size - _ptr);
+		if ( (nr = nb) > 0 ) {
+			memmove(buff, (const char *)_data+(size_t)_ptr, nb);
+			_ptr += nb;
+		}
+		return true;
+	}
+
+	virtual bool Write( void *, DWORD, DWORD& ) { return false; } //...
+};	
Index: fileview.hpp
===================================================================
--- fileview.hpp	(revision 6469)
+++ fileview.hpp	(working copy)
@@ -104,4 +104,6 @@
 		__int64 GetViewFilePos() const;
 		void ShowStatus();
 		int GetId(void) const { return View.ViewerID; };
+
+		void SetVFile( VFile *vf ) { View.SetVFile(vf); }
 };
Index: viewer.hpp
===================================================================
--- viewer.hpp	(revision 6469)
+++ viewer.hpp	(working copy)
@@ -38,6 +38,7 @@
 #include "plugin.hpp"
 #include "poscache.hpp"
 #include "config.hpp"
+#include "vFile.hpp"
 #include "cache.hpp"
 
 #define MAXSCRY       512                    // 300   // 120
@@ -174,6 +175,8 @@
 		int  vgetc_ib;
 		wchar_t vgetc_composite;
 
+		VFile *vFile;
+
 	private:
 		virtual void DisplayObject();
 
@@ -220,6 +223,12 @@
 		bool veof();
 		wchar_t vgetc_prev();
 
+		bool vOpened();
+		bool vClose();
+		bool vOpen( const wchar_t *fname );
+
+		bool vGetFileFormat(UINT& cp, bool bHeuristic);
+
 		void SetFileSize();
 		int GetStrBytesNum(const wchar_t *Str, int Length);
 
@@ -297,4 +306,6 @@
 		int ProcessTypeWrapMode(int newMode, bool isRedraw=TRUE);
 
 		void SearchTextTransform(UnicodeString &to, const wchar_t *from, bool hex2text, int &pos);
+
+		void SetVFile( VFile *vf );
 };
Index: cache.cpp
===================================================================
--- cache.cpp	(revision 6469)
+++ cache.cpp	(working copy)
@@ -34,17 +34,18 @@
 #pragma hdrstop
 
 #include "cache.hpp"
+#include "vFile.hpp"
 
 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));
+	vFile = nullptr;
 }
 
 CachedRead::~CachedRead()
@@ -52,15 +53,17 @@
 	xf_free(Buffer);
 }
 
-bool CachedRead::AdjustAlignment()
+bool CachedRead::AdjustAlignment( VFile *vf )
 {
-	if (!file.Opened())
+	vFile = vf;
+
+	if ( !vFile && !file.Opened() )
 		return false;
 
 	DWORD ret, buff_size = BufferSize;
 	DISK_GEOMETRY g;
 
-	if (file.IoControl(IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr,0, &g,(DWORD)sizeof(g), &ret,nullptr))
+	if (!vFile && file.IoControl(IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr,0, &g,(DWORD)sizeof(g), &ret,nullptr))
 	{
 		if (g.BytesPerSector > 512 && g.BytesPerSector <= 256*1024)
 		{
@@ -90,7 +93,7 @@
 
 bool CachedRead::Read(LPVOID Data, DWORD DataSize, LPDWORD BytesRead)
 {
-	INT64 Ptr = file.GetPointer();
+	INT64 Ptr = vFile ? vFile->GetPointer() : file.GetPointer();
 
 	if(Ptr!=LastPtr)
 	{
@@ -121,18 +124,22 @@
 
 			Result=true;
 
-			DWORD Actual=Min(BytesLeft, DataSize);
+			DWORD Actual = Min(BytesLeft, DataSize);
 			memcpy(Data, &Buffer[ReadSize-BytesLeft], Actual);
-			Data=((LPBYTE)Data)+Actual;
-			BytesLeft-=Actual;
-			file.SetPointer(Actual, &LastPtr, FILE_CURRENT);
-			*BytesRead+=Actual;
-			DataSize-=Actual;
+			Data = ((LPBYTE)Data)+Actual;
+			BytesLeft -= Actual;
+			if ( vFile )
+				vFile->SetPointer(Actual, &LastPtr, FILE_CURRENT);
+			else
+				file.SetPointer(Actual, &LastPtr, FILE_CURRENT);
+
+			*BytesRead += Actual;
+			DataSize -= Actual;
 		}
 	}
 	else
 	{
-		Result = file.Read(Data, DataSize, *BytesRead);
+		Result = vFile ? vFile->Read(Data, DataSize, *BytesRead) : file.Read(Data, DataSize, *BytesRead);
 	}
 	return Result;
 }
@@ -143,7 +150,10 @@
 	{
 		BytesLeft += BytesUnread;
 		__int64 off = BytesUnread;
-		file.SetPointer(-off, &LastPtr, FILE_CURRENT);
+		if ( vFile)
+			vFile->SetPointer(-off, &LastPtr, FILE_CURRENT);
+		else
+			file.SetPointer(-off, &LastPtr, FILE_CURRENT);
 		return true;
 	}
 	return false;
@@ -152,29 +162,39 @@
 bool CachedRead::FillBuffer()
 {
 	bool Result=false;
-	if (!file.Eof())
+	if ( (vFile && !vFile->Eof()) || (!vFile && !file.Eof()) )
 	{
-		INT64 Pointer = file.GetPointer();
+		INT64 Pointer = vFile ? vFile->GetPointer() : file.GetPointer();
 
 		int shift = (int)(Pointer % Alignment);
 		if (Pointer-shift > BufferSize/2)
 			shift += BufferSize/2;
 
-		if (shift)
-			file.SetPointer(-shift, nullptr, FILE_CURRENT);
+		if ( shift ) {
+			if ( vFile )
+				vFile->SetPointer(-shift, nullptr, FILE_CURRENT);
+			else
+				file.SetPointer(-shift, nullptr, FILE_CURRENT);
+		}
 
 		DWORD read_size = BufferSize;
-		UINT64 FileSize = 0;
-		if (file.GetSize(FileSize) && Pointer-shift+BufferSize > (INT64)FileSize)
-			read_size = (DWORD)((INT64)FileSize-Pointer+shift);
+		union { UINT64 u64FileSize; INT64 i64FileSize; } u;
+		u.i64FileSize = 0;
+		bool ok_size = vFile ? vFile->GetSize(&u.i64FileSize) : file.GetSize(u.u64FileSize);
 
-		Result = file.Read(Buffer, read_size, ReadSize);
+		if (ok_size && Pointer-shift+BufferSize > u.i64FileSize)
+			read_size = (DWORD)(u.i64FileSize-Pointer+shift);
+
+		Result = vFile ? vFile->Read(Buffer, read_size, ReadSize) : file.Read(Buffer, read_size, ReadSize);
 		if (Result)
 		{
 			if (ReadSize > (DWORD)shift)
 			{
 				BytesLeft = ReadSize - shift;
-				file.SetPointer(Pointer, nullptr, FILE_BEGIN);
+				if ( vFile )
+					vFile->SetPointer(Pointer, nullptr, FILE_BEGIN);
+				else
+					file.SetPointer(Pointer, nullptr, FILE_BEGIN);
 			}
 			else
 			{
@@ -183,8 +203,12 @@
 		}
 		else
 		{
-			if (shift)
-				file.SetPointer(Pointer, nullptr, FILE_BEGIN);
+			if (shift) {
+				if ( vFile )
+					vFile->SetPointer(Pointer, nullptr, FILE_BEGIN);
+				else
+					file.SetPointer(Pointer, nullptr, FILE_BEGIN);
+			}
 			ReadSize=0;
 			BytesLeft=0;
 		}
@@ -214,13 +238,13 @@
 bool CachedWrite::Write(LPCVOID Data, DWORD DataSize)
 {
 	bool Result=false;
-	bool SuccessFlush=true;
+	bool SuccessFlush = true;
 
-	if (Buffer)
+	if ( Buffer )
 	{
 		if (DataSize>FreeSize)
 		{
-			SuccessFlush=Flush();
+			SuccessFlush = Flush();
 		}
 
 		if(SuccessFlush)
@@ -228,8 +252,9 @@
 			if (DataSize>FreeSize)
 			{
 				DWORD WrittenSize=0;
+				bool ok_wr = file.Write(Data,DataSize,WrittenSize);
 
-				if (file.Write(Data, DataSize,WrittenSize) && DataSize==WrittenSize)
+				if (ok_wr && DataSize==WrittenSize)
 				{
 					Result=true;
 				}
@@ -253,8 +278,9 @@
 		if (!Flushed)
 		{
 			DWORD WrittenSize=0;
+			bool ok_wr = file.Write(Buffer,BufferSize-FreeSize,WrittenSize);
 
-			if (file.Write(Buffer, BufferSize-FreeSize, WrittenSize, nullptr) && BufferSize-FreeSize==WrittenSize)
+			if (ok_wr && BufferSize-FreeSize==WrittenSize)
 			{
 				Flushed=true;
 				FreeSize=BufferSize;
Index: filestr.hpp
===================================================================
--- filestr.hpp	(revision 6469)
+++ filestr.hpp	(working copy)
@@ -105,4 +105,7 @@
 		int GetUnicodeString(LPWSTR* DestStr, int& Length, bool bBigEndian);
 };
 
-bool GetFileFormat(File& file, UINT& nCodePage, bool* pSignatureFound = nullptr, bool bUseHeuristics = true);
\ No newline at end of file
+bool GetFileFormat(File& file, UINT& nCodePage, bool* pSignatureFound = nullptr, bool bUseHeuristics = true);
+
+class VFile;
+bool GetFileFormat(VFile *vf, UINT& nCodePage, bool* pSignatureFound = nullptr, bool bUseHeuristics = true);
Index: viewer.cpp
===================================================================
--- viewer.cpp	(revision 6469)
+++ viewer.cpp	(working copy)
@@ -158,16 +158,46 @@
 
 	memset(&vString, 0, sizeof(vString));
 	vString.lpData = new wchar_t[MAX_VIEWLINEB];
+
+	vFile = nullptr;
 }
 
+void Viewer::SetVFile( VFile *vf )
+{
+	vFile = vf;
+}
 
+bool Viewer::vOpened()
+{
+	return vFile || ViewFile.Opened();
+}
+
+bool Viewer::vClose()
+{
+	return vFile || ViewFile.Close();
+}
+
+bool Viewer::vOpen( const wchar_t *fname )
+{
+	return vFile || ViewFile.Open(fname,FILE_READ_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,nullptr,OPEN_EXISTING);
+}
+
+bool Viewer::vGetFileFormat(UINT& cp, bool bHeuristic)
+{
+	bool detect = vFile
+		? GetFileFormat(vFile, cp, &Signature, bHeuristic)
+		: GetFileFormat(ViewFile, cp, &Signature, bHeuristic
+	);
+	return detect;
+}
+
 Viewer::~Viewer()
 {
 	KeepInitParameters();
 
-	if (ViewFile.Opened())
+	if (vOpened())
 	{
-		ViewFile.Close();
+		vClose();
 
 		if (Opt.ViOpt.SavePos)
 		{
@@ -245,21 +275,43 @@
 	//InitHex=VM.Hex;
 }
 
+static bool IsDriveTypeFLOPPY( const string &strRoot ) // media have to be inserted...
+{
+	bool floppy = true; // returns true if can't open drive
 
+	string drive = HasPathPrefix(strRoot) ? strRoot : L"\\\\?\\" + strRoot;
+	DeleteEndSlash(drive, false);
+
+	HANDLE hDevice = ::CreateFileW(
+		drive.CPtr(),
+		GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, 0, nullptr
+	);
+	if ( INVALID_HANDLE_VALUE != hDevice )
+	{
+		DISK_GEOMETRY g;
+		DWORD dwOutBytes;
+		if ( DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL,0, &g,(DWORD)sizeof(g), &dwOutBytes,NULL)	)
+			floppy = ( g.MediaType != FixedMedia && g.MediaType != RemovableMedia );
+		CloseHandle(hDevice);
+	}
+	return floppy;
+}
+
 int Viewer::OpenFile(const wchar_t *Name,int warning)
 {
 	VM.CodePage=DefCodePage;
 	DefCodePage=CP_AUTODETECT;
 	OpenFailed=false;
 
-	ViewFile.Close();
+	vClose();
+
 	Reader.Clear();
 	vgetc_ready = lcache_ready = false;
 
 	SelectSize = -1; // ������� ��������
 	strFileName = Name;
 
-	if (Opt.OnlyEditorViewerUsed && !StrCmp(strFileName, L"-"))
+	if (!vFile && Opt.OnlyEditorViewerUsed && !StrCmp(strFileName, L"-"))
 	{
 		string strTempName;
 
@@ -290,10 +342,10 @@
 	}
 	else
 	{
-		ViewFile.Open(strFileName, FILE_READ_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, nullptr, OPEN_EXISTING);
+		vOpen(strFileName.CPtr());
 	}
 
-	if (!ViewFile.Opened())
+	if (!vOpened())
 	{
 		/* $ 04.07.2000 tran
 		   + 'warning' flag processing, in QuickView it is FALSE
@@ -305,12 +357,21 @@
 		OpenFailed=true;
 		return FALSE;
 	}
-	Reader.AdjustAlignment();
+	Reader.AdjustAlignment(vFile);
 
 	CodePageChangedByUser=FALSE;
 
-	ConvertNameToFull(strFileName,strFullFileName);
-	apiGetFindDataEx(strFileName, ViewFindData);
+	if ( vFile )
+	{
+		vFile->GetName(strFullFileName, true);
+		vFile->GetSize((PINT64)&ViewFindData.nFileSize);
+		vFile->GetUpdateTime(&ViewFindData.ftLastWriteTime);
+	}
+	else
+	{
+		ConvertNameToFull(strFileName,strFullFileName);
+		apiGetFindDataEx(strFileName, ViewFindData);
+	}
 	UINT CachedCodePage=0;
 
 	if (Opt.ViOpt.SavePos && !ReadStdin)
@@ -349,7 +410,7 @@
 
 		if (VM.CodePage == CP_AUTODETECT || IsUnicodeOrUtfCodePage(VM.CodePage))
 		{
-			Detect=GetFileFormat(ViewFile,CodePage,&Signature,Opt.ViOpt.AutoDetectCodePage!=0);
+			Detect = vGetFileFormat(CodePage, Opt.ViOpt.AutoDetectCodePage != 0);
 
 			// �������� ������������� ��� ��� ���������������� ������ �������
 			if (Detect)
@@ -377,7 +438,7 @@
 			CodePageChangedByUser=TRUE;
 		}
 
-		ViewFile.SetPointer(0, nullptr, FILE_BEGIN);
+		vseek(0, FILE_BEGIN);
 	}
 	SetFileSize();
 
@@ -393,19 +454,23 @@
 	bVE_READ_Sent = true;
 
 	last_update_check = GetTickCount();
-	string strRoot;
-	GetPathRoot(strFullFileName, strRoot);
-	int DriveType = FAR_GetDriveType(strRoot);
-	if (IsDriveTypeCDROM(DriveType))
-		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: 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
+	if ( vFile )
+		update_check_period = vFile->UpdateCheckPeriod();
+	else {
+		string strRoot;
+		GetPathRoot(strFullFileName, strRoot);
+		int DriveType = FAR_GetDriveType(strRoot);
+		if (IsDriveTypeCDROM(DriveType))
+			DriveType = DRIVE_CDROM;
+		switch (DriveType)
+		{                                                    // floppy: never, flash drive: 0.5 sec
+			case DRIVE_REMOVABLE: update_check_period = IsDriveTypeFLOPPY(strRoot) ? -1 : 500; break;
+			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;
@@ -431,7 +496,7 @@
 	int I,Y;
 	AdjustWidth();
 
-	if (!ViewFile.Opened())
+	if (!vOpened())
 	{
 		if (!strFileName.IsEmpty() && ((nMode == SHOW_RELOAD) || (nMode == SHOW_HEX)))
 		{
@@ -1128,9 +1193,9 @@
 		case MCODE_C_SELECTED:
 			return (__int64)(SelectSize >= 0 ?TRUE:FALSE);
 		case MCODE_C_EOF:
-			return (__int64)(LastPage || !ViewFile.Opened());
+			return (__int64)(LastPage || !vOpened());
 		case MCODE_C_BOF:
-			return (__int64)(!FilePos || !ViewFile.Opened());
+			return (__int64)(!FilePos || !vOpened());
 		case MCODE_V_VIEWERSTATE:
 		{
 			DWORD MacroViewerState=0;
@@ -1218,7 +1283,7 @@
 		case KEY_CTRLC:
 		case KEY_CTRLINS:  case KEY_CTRLNUMPAD0:
 		{
-			if (SelectSize >= 0 && ViewFile.Opened())
+			if (SelectSize >= 0 && vOpened())
 			{
 				wchar_t *SelData = (wchar_t*)xf_malloc((size_t)SelectSize+1);
 				if ( SelData )
@@ -1248,7 +1313,7 @@
 		}
 		case KEY_IDLE:
 		{
-			if (ViewFile.Opened() && update_check_period >= 0)
+			if (vOpened() && update_check_period >= 0)
 			{
 				DWORD now_ticks = GetTickCount();
 				if ((int)(now_ticks - last_update_check) < update_check_period)
@@ -1256,7 +1321,11 @@
 				last_update_check = now_ticks;
 
 				FAR_FIND_DATA_EX NewViewFindData;
-				if (!apiGetFindDataEx(strFullFileName, NewViewFindData))
+				bool ok = vFile
+					? vFile->GetSize((PINT64)&NewViewFindData.nFileSize) && vFile->GetUpdateTime(&NewViewFindData.ftLastWriteTime)
+					: apiGetFindDataEx(strFullFileName, NewViewFindData) != 0
+				;
+				if ( !ok )
 					return TRUE;
 
 				if (ViewFindData.ftLastWriteTime.dwLowDateTime!=NewViewFindData.ftLastWriteTime.dwLowDateTime
@@ -1267,7 +1336,8 @@
 					SetFileSize();
 
 					Reader.Clear(); // ���� ���� �� ��� ����?
-					ViewFile.FlushBuffers();
+					if ( !vFile )
+						ViewFile.FlushBuffers();
 					vseek(0, SEEK_CUR); // reset vgetc state
 					lcache_ready = false; // reset start-lines cache
 
@@ -1424,7 +1494,7 @@
 				if (nCodePage == (CP_AUTODETECT & 0xffff))
 				{
 					__int64 fpos = vtell();
-					bool detect = GetFileFormat(ViewFile,nCodePage,&Signature,true) && IsCodePageSupported(nCodePage);
+					bool detect = vGetFileFormat(nCodePage, true) && IsCodePageSupported(nCodePage);
 					vseek(fpos, SEEK_SET);
 					if (!detect)
 						nCodePage = Opt.ViOpt.AnsiCodePageAsDefault ? GetACP() : GetOEMCP();
@@ -1440,7 +1510,7 @@
 		}
 		case KEY_ALTF8:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				LastPage = 0;
 				GoTo();
@@ -1498,7 +1568,7 @@
 		}
 		case KEY_UP: case KEY_NUMPAD8: case KEY_SHIFTNUMPAD8:
 		{
-			if (FilePos>0 && ViewFile.Opened())
+			if (FilePos>0 && vOpened())
 			{
 				Up(1);	// LastPage = 0
 
@@ -1519,7 +1589,7 @@
 		}
 		case KEY_DOWN: case KEY_NUMPAD2:  case KEY_SHIFTNUMPAD2:
 		{
-			if (!LastPage && ViewFile.Opened())
+			if (!LastPage && vOpened())
 			{
 				if (VM.Hex)
 				{
@@ -1534,7 +1604,7 @@
 		}
 		case KEY_PGUP: case KEY_NUMPAD9: case KEY_SHIFTNUMPAD9: case KEY_CTRLUP:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				Up(Y2-Y1);
 				Show();
@@ -1544,7 +1614,7 @@
 		}
 		case KEY_PGDN: case KEY_NUMPAD3:  case KEY_SHIFTNUMPAD3: case KEY_CTRLDOWN:
 		{
-			if (LastPage || !ViewFile.Opened())
+			if (LastPage || !vOpened())
 				return TRUE;
 
 			FilePos = EndOfScreen(-1); // start of last screen line
@@ -1572,7 +1642,7 @@
 		}
 		case KEY_LEFT: case KEY_NUMPAD4: case KEY_SHIFTNUMPAD4:
 		{
-			if (LeftPos>0 && ViewFile.Opened())
+			if (LeftPos>0 && vOpened())
 			{
 				if (VM.Hex && LeftPos>80-Width)
 					LeftPos=Max(80-Width,1);
@@ -1585,7 +1655,7 @@
 		}
 		case KEY_RIGHT: case KEY_NUMPAD6: case KEY_SHIFTNUMPAD6:
 		{
-			if (LeftPos<MAX_VIEWLINE && ViewFile.Opened() && !VM.Hex && !VM.Wrap)
+			if (LeftPos<MAX_VIEWLINE && vOpened() && !VM.Hex && !VM.Wrap)
 			{
 				LeftPos++;
 				Show();
@@ -1595,7 +1665,7 @@
 		}
 		case KEY_CTRLLEFT: case KEY_CTRLNUMPAD4:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				if (VM.Hex)
 				{
@@ -1613,7 +1683,7 @@
 		}
 		case KEY_CTRLRIGHT: case KEY_CTRLNUMPAD6:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				if (VM.Hex)
 				{
@@ -1635,7 +1705,7 @@
 		case KEY_CTRLSHIFTLEFT:    case KEY_CTRLSHIFTNUMPAD4:
 
 			// ������� �� ����� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				LeftPos = 0;
 				Show();
@@ -1645,7 +1715,7 @@
 		case KEY_CTRLSHIFTRIGHT:     case KEY_CTRLSHIFTNUMPAD6:
 		{
 			// ������� �� ���� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				int I, Y, Len, MaxLen = 0;
 
@@ -1671,11 +1741,11 @@
 		case KEY_HOME:        case KEY_NUMPAD7:   case KEY_SHIFTNUMPAD7:
 
 			// ������� �� ����� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 				LeftPos=0;
 
 		case KEY_CTRLPGUP:    case KEY_CTRLNUMPAD9:
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				FilePos=0;
 				Show();
@@ -1686,12 +1756,12 @@
 		case KEY_END:         case KEY_NUMPAD1: case KEY_SHIFTNUMPAD1:
 
 			// ������� �� ���� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 				LeftPos=0;
 
 		case KEY_CTRLPGDN:    case KEY_CTRLNUMPAD3:
 
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				/* $ 15.08.2002 IS
 				   �� ������ ������, ���� ������� ������ �� �������� �������
@@ -1981,7 +2051,7 @@
 {
 	assert( nlines > 0 );
 
-	if (!ViewFile.Opened())
+	if (!vOpened())
 		return;
 
 	LastPage = 0;
@@ -2996,7 +3066,7 @@
 */
 void Viewer::Search(int Next,int FirstChar)
 {
-	if (!ViewFile.Opened() || (Next && strLastSearchStr.IsEmpty()))
+	if (!vOpened() || (Next && strLastSearchStr.IsEmpty()))
 		return;
 
 	string strSearchStr, strMsgStr;
@@ -3541,12 +3611,16 @@
 	}
 
 	vgetc_ready = false;
-	return ViewFile.SetPointer(Offset, nullptr, Whence);
+
+	return vFile
+		? vFile->SetPointer(Offset, nullptr, Whence)
+		: ViewFile.SetPointer(Offset, nullptr, Whence)
+	;
 }
 
 __int64 Viewer::vtell()
 {
-	__int64 Ptr = ViewFile.GetPointer();
+	__int64 Ptr = vFile ? vFile->GetPointer() : ViewFile.GetPointer();
 
 	if (vgetc_ready)
 		Ptr -= (vgetc_cb - vgetc_ib);
@@ -3559,7 +3633,7 @@
 	if (vgetc_ready && vgetc_ib < vgetc_cb)
 		return false;
 	else
-		return ViewFile.Eof();
+		return vFile ? vFile->Eof() : ViewFile.Eof();
 }
 
 bool Viewer::vgetc(wchar_t *pCh)
@@ -3567,7 +3641,7 @@
 	if (!vgetc_ready)
 		vgetc_cb = vgetc_ib = (int)(vgetc_composite = 0);
 
-	if (vgetc_cb - vgetc_ib < 4 && !ViewFile.Eof())
+	if (vgetc_cb - vgetc_ib < 4 && !(vFile ? vFile->Eof() : ViewFile.Eof()))
 	{
 		vgetc_cb -= vgetc_ib;
 		if (vgetc_cb && vgetc_ib)
@@ -3853,12 +3927,18 @@
 
 void Viewer::SetFileSize()
 {
-	if (!ViewFile.Opened())
+	if (!vOpened())
 		return;
 
-	UINT64 uFileSize=0; // BUGBUG, sign
-	ViewFile.GetSize(uFileSize);
-	FileSize=uFileSize;
+	union { UINT64 u64FileSize; INT64 i64FileSize; } u;
+	u.i64FileSize = 0;
+
+	if ( vFile )
+		vFile->GetSize(&u.i64FileSize);
+	else
+		ViewFile.GetSize(u.u64FileSize);
+
+	FileSize = u.i64FileSize;
 }
 
 
@@ -3874,7 +3954,7 @@
 //
 void Viewer::SelectText(const __int64 &match_pos,const __int64 &search_len, const DWORD flags)
 {
-	if (!ViewFile.Opened())
+	if (!vOpened())
 		return;
 
 	SelectPos = match_pos;
Index: plugin.hpp
===================================================================
--- plugin.hpp	(revision 6469)
+++ plugin.hpp	(working copy)
@@ -853,7 +853,8 @@
 	VF_ENABLE_F6             = 0x0000000000000004ULL,
 	VF_DISABLEHISTORY        = 0x0000000000000008ULL,
 	VF_IMMEDIATERETURN       = 0x0000000000000100ULL,
-	VF_DELETEONLYFILEONCLOSE = 0x0000000000000200ULL;
+	VF_DELETEONLYFILEONCLOSE = 0x0000000000000200ULL,
+	VF_VFILE                 = 0x0000000000000400ULL;
 
 typedef int (WINAPI *FARAPIVIEWER)(
     const wchar_t *FileName,
Virtual_Viewer1.diff (29,052 bytes)   

2useven10

2011-07-21 13:19

developer   bugnote:0007289

можно воспользоваться фичей через plugin api (FarViewer).
Ho ОООчень некошерно - если выставлен флаг VF_VFILE (добавлен), вместо имени
файла передаётся указатель на интерфейс VFile. Это временный костыль, надо править.

2useven10

2011-07-22 12:56

developer  

Virtual_Viewer2.diff (29,038 bytes)   
Index: filestr.cpp
===================================================================
--- filestr.cpp	(revision 6475)
+++ filestr.cpp	(working copy)
@@ -905,36 +905,78 @@
 	return ExitCode;
 }
 
+class RegularFile : public VFile
+{
+private:
+	File&  _file;
+	string _fnam;
+	int  _ucheck;
+
+public:
+	RegularFile(File &file, int ucheck = -1) : _file(file), _ucheck(ucheck) {}
+	~RegularFile() {}
+
+	virtual int Version() { return VFile_Version_Current; }
+
+	virtual bool GetName( string &fname, bool full ) {
+		fname.Clear();
+		if ( !_file.Opened() )
+			return false;
+		if ( !full )
+			fname = _fnam;
+		else
+			ConvertNameToFull( _fnam.CPtr(), fname);
+		return true;
+	}
+
+	virtual bool SetPointer( INT64 off, PINT64 ppos, int whence ) { return _file.SetPointer(off,ppos,(DWORD)whence);}
+	virtual INT64 GetPointer() { return _file.GetPointer(); }
+	virtual bool Eof() { return _file.Eof(); } 
+
+	virtual bool GetSize( INT64 *fsize ) { UINT64 usz=0; bool r = _file.GetSize(usz); *fsize=(UINT64)usz; return r; }
+	virtual bool GetUpdateTime( FILETIME *ftime ) { return _file.GetTime(nullptr, nullptr, ftime, nullptr); }
+	virtual int UpdateCheckPeriod() { return _ucheck; }
+
+	virtual bool Read( void *buff, DWORD nb, DWORD& nr ) { return _file.Read( buff, nb, nr, nullptr); }
+	virtual bool Write( const void *buff, DWORD nb, DWORD& nw ) { return _file.Write( buff, nb, nw, nullptr); }
+};	
+
 bool GetFileFormat(File& file, UINT& nCodePage, bool* pSignatureFound, bool bUseHeuristics)
 {
+	RegularFile vf(file);
+	return GetFileFormat(&vf, nCodePage, pSignatureFound, bUseHeuristics);
+}
+
+bool GetFileFormat(VFile *vf, UINT& nCodePage, bool* pSignatureFound, bool bUseHeuristics)
+{
 	DWORD dwTemp=0;
 	bool bSignatureFound = false;
 	bool bDetect=false;
 
 	DWORD Readed = 0;
-	if (file.Read(&dwTemp, sizeof(dwTemp), Readed) && Readed > 1 ) // minimum signature size is 2 bytes
+	if (vf->Read(&dwTemp, sizeof(dwTemp), Readed) && Readed > 1 ) // minimum signature size is 2 bytes
 	{
 		if (LOWORD(dwTemp) == SIGN_UNICODE)
 		{
 			nCodePage = CP_UNICODE;
-			file.SetPointer(2, nullptr, FILE_BEGIN);
+			vf->SetPointer(2, nullptr, FILE_BEGIN);
 			bSignatureFound = true;
 		}
 		else if (LOWORD(dwTemp) == SIGN_REVERSEBOM)
 		{
 			nCodePage = CP_REVERSEBOM;
-			file.SetPointer(2, nullptr, FILE_BEGIN);
+			vf->SetPointer(2, nullptr, FILE_BEGIN);
 			bSignatureFound = true;
 		}
 		else if ((dwTemp & 0x00FFFFFF) == SIGN_UTF8)
 		{
 			nCodePage = CP_UTF8;
-			file.SetPointer(3, nullptr, FILE_BEGIN);
+			vf->SetPointer(3, nullptr, FILE_BEGIN);
 			bSignatureFound = true;
 		}
 		else
 		{
-			file.SetPointer(0, nullptr, FILE_BEGIN);
+			vf->SetPointer(0, nullptr, FILE_BEGIN);
 		}
 	}
 
@@ -944,12 +986,12 @@
 	}
 	else if (bUseHeuristics)
 	{
-		file.SetPointer(0, nullptr, FILE_BEGIN);
+		vf->SetPointer(0, nullptr, FILE_BEGIN);
 		DWORD Size=0x8000; // BUGBUG. TODO: configurable
 		LPVOID Buffer=xf_malloc(Size);
 		DWORD ReadSize = 0;
-		bool ReadResult = file.Read(Buffer, Size, ReadSize);
-		file.SetPointer(0, nullptr, FILE_BEGIN);
+		bool ReadResult = vf->Read(Buffer, Size, ReadSize);
+		vf->SetPointer(0, nullptr, FILE_BEGIN);
 
 		if (ReadResult && ReadSize)
 		{
Index: plugapi.cpp
===================================================================
--- plugapi.cpp	(revision 6475)
+++ plugapi.cpp	(working copy)
@@ -1796,12 +1796,19 @@
 	xf_free(PanelItem);
 }
 
-int WINAPI FarViewer(const wchar_t *FileName,const wchar_t *Title,
+static int far_viewer(const wchar_t *FileName, VFile *vf, const wchar_t *Title,
                      int X1,int Y1,int X2, int Y2,unsigned __int64 Flags, UINT CodePage)
 {
 	if (FrameManager->ManagerIsDown())
 		return FALSE;
 
+	string fname;
+	if ( !FileName && vf )
+	{
+		vf->GetName(fname);
+		FileName = fname.CPtr();
+	}
+
 	class ConsoleTitle ct;
 	int DisableHistory=(Flags & VF_DISABLEHISTORY)?TRUE:FALSE;
 
@@ -1819,6 +1826,8 @@
 		if (!Viewer)
 			return FALSE;
 
+		Viewer->SetVFile(vf);
+
 		/* $ 14.06.2002 IS
 		   ��������� VF_DELETEONLYFILEONCLOSE - ���� ���� ����� ����� ������
 		   ��������� �� �������� � VF_DELETEONCLOSE
@@ -1853,6 +1862,8 @@
 		FrameManager->ExecuteModal();
 		FrameManager->ExitModalEV();
 
+		Viewer.SetVFile(vf);
+
 		/* $ 14.06.2002 IS
 		   ��������� VF_DELETEONLYFILEONCLOSE - ���� ���� ����� ����� ������
 		   ��������� �� �������� � VF_DELETEONCLOSE
@@ -1871,7 +1882,18 @@
 	return TRUE;
 }
 
+int WINAPI FarViewer(const wchar_t *FileName, const wchar_t *Title,
+	int X1,int Y1,int X2, int Y2,unsigned __int64 Flags, UINT CodePage)
+{
+	return far_viewer(FileName, nullptr, Title, X1,Y1, X2,Y2, Flags, CodePage);
+}
 
+int WINAPI FarViewerVFile(VFile *vf, const wchar_t *Title,
+	int X1,int Y1,int X2, int Y2,unsigned __int64 Flags, UINT CodePage)
+{
+	return far_viewer(nullptr, vf, Title, X1,Y1, X2,Y2, Flags, CodePage);
+}
+
 int WINAPI FarEditor(
     const wchar_t *FileName,
     const wchar_t *Title,
Index: cache.hpp
===================================================================
--- cache.hpp	(revision 6475)
+++ cache.hpp	(working copy)
@@ -32,12 +32,14 @@
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+class VFile;
+
 class CachedRead
 {
 public:
 	CachedRead(File& file, DWORD buffer_size=0);
 	~CachedRead();
-	bool AdjustAlignment(); // file have to be opened already
+	bool AdjustAlignment(VFile *vf=nullptr); // file have to be opened already
 	bool Read(LPVOID Data, DWORD DataSize, LPDWORD BytesRead);
 	bool FillBuffer();
 	bool Unread(DWORD BytesUnread);
@@ -52,6 +54,7 @@
 	INT64 LastPtr;
 	DWORD BufferSize; // = 2*k*Alignment (k >= 2)
 	int   Alignment;  //
+	VFile *vFile;
 };
 
 
@@ -69,5 +72,4 @@
 	enum {BufferSize=0x10000};
 	DWORD FreeSize;
 	bool Flushed;
-
 };
Index: fileview.hpp
===================================================================
--- fileview.hpp	(revision 6475)
+++ fileview.hpp	(working copy)
@@ -104,4 +104,6 @@
 		__int64 GetViewFilePos() const;
 		void ShowStatus();
 		int GetId(void) const { return View.ViewerID; };
+
+		void SetVFile( VFile *vf ) { View.SetVFile(vf); }
 };
Index: viewer.hpp
===================================================================
--- viewer.hpp	(revision 6475)
+++ viewer.hpp	(working copy)
@@ -174,6 +174,8 @@
 		int  vgetc_ib;
 		wchar_t vgetc_composite;
 
+		VFile *vFile;
+
 	private:
 		virtual void DisplayObject();
 
@@ -220,6 +222,12 @@
 		bool veof();
 		wchar_t vgetc_prev();
 
+		bool vOpened();
+		bool vClose();
+		bool vOpen( const wchar_t *fname );
+
+		bool vGetFileFormat(UINT& cp, bool bHeuristic);
+
 		void SetFileSize();
 		int GetStrBytesNum(const wchar_t *Str, int Length);
 
@@ -297,4 +305,6 @@
 		int ProcessTypeWrapMode(int newMode, bool isRedraw=TRUE);
 
 		void SearchTextTransform(UnicodeString &to, const wchar_t *from, bool hex2text, int &pos);
+
+		void SetVFile( VFile *vf );
 };
Index: cache.cpp
===================================================================
--- cache.cpp	(revision 6475)
+++ cache.cpp	(working copy)
@@ -34,17 +34,18 @@
 #pragma hdrstop
 
 #include "cache.hpp"
+#include "plugin.hpp"
 
 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));
+	vFile = nullptr;
 }
 
 CachedRead::~CachedRead()
@@ -52,15 +53,17 @@
 	xf_free(Buffer);
 }
 
-bool CachedRead::AdjustAlignment()
+bool CachedRead::AdjustAlignment( VFile *vf )
 {
-	if (!file.Opened())
+	vFile = vf;
+
+	if ( !vFile && !file.Opened() )
 		return false;
 
 	DWORD ret, buff_size = BufferSize;
 	DISK_GEOMETRY g;
 
-	if (file.IoControl(IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr,0, &g,(DWORD)sizeof(g), &ret,nullptr))
+	if (!vFile && file.IoControl(IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr,0, &g,(DWORD)sizeof(g), &ret,nullptr))
 	{
 		if (g.BytesPerSector > 512 && g.BytesPerSector <= 256*1024)
 		{
@@ -90,7 +93,7 @@
 
 bool CachedRead::Read(LPVOID Data, DWORD DataSize, LPDWORD BytesRead)
 {
-	INT64 Ptr = file.GetPointer();
+	INT64 Ptr = vFile ? vFile->GetPointer() : file.GetPointer();
 
 	if(Ptr!=LastPtr)
 	{
@@ -121,18 +124,22 @@
 
 			Result=true;
 
-			DWORD Actual=Min(BytesLeft, DataSize);
+			DWORD Actual = Min(BytesLeft, DataSize);
 			memcpy(Data, &Buffer[ReadSize-BytesLeft], Actual);
-			Data=((LPBYTE)Data)+Actual;
-			BytesLeft-=Actual;
-			file.SetPointer(Actual, &LastPtr, FILE_CURRENT);
-			*BytesRead+=Actual;
-			DataSize-=Actual;
+			Data = ((LPBYTE)Data)+Actual;
+			BytesLeft -= Actual;
+			if ( vFile )
+				vFile->SetPointer(Actual, &LastPtr, FILE_CURRENT);
+			else
+				file.SetPointer(Actual, &LastPtr, FILE_CURRENT);
+
+			*BytesRead += Actual;
+			DataSize -= Actual;
 		}
 	}
 	else
 	{
-		Result = file.Read(Data, DataSize, *BytesRead);
+		Result = vFile ? vFile->Read(Data, DataSize, *BytesRead) : file.Read(Data, DataSize, *BytesRead);
 	}
 	return Result;
 }
@@ -143,7 +150,10 @@
 	{
 		BytesLeft += BytesUnread;
 		__int64 off = BytesUnread;
-		file.SetPointer(-off, &LastPtr, FILE_CURRENT);
+		if ( vFile)
+			vFile->SetPointer(-off, &LastPtr, FILE_CURRENT);
+		else
+			file.SetPointer(-off, &LastPtr, FILE_CURRENT);
 		return true;
 	}
 	return false;
@@ -152,29 +162,39 @@
 bool CachedRead::FillBuffer()
 {
 	bool Result=false;
-	if (!file.Eof())
+	if ( (vFile && !vFile->Eof()) || (!vFile && !file.Eof()) )
 	{
-		INT64 Pointer = file.GetPointer();
+		INT64 Pointer = vFile ? vFile->GetPointer() : file.GetPointer();
 
 		int shift = (int)(Pointer % Alignment);
 		if (Pointer-shift > BufferSize/2)
 			shift += BufferSize/2;
 
-		if (shift)
-			file.SetPointer(-shift, nullptr, FILE_CURRENT);
+		if ( shift ) {
+			if ( vFile )
+				vFile->SetPointer(-shift, nullptr, FILE_CURRENT);
+			else
+				file.SetPointer(-shift, nullptr, FILE_CURRENT);
+		}
 
 		DWORD read_size = BufferSize;
-		UINT64 FileSize = 0;
-		if (file.GetSize(FileSize) && Pointer-shift+BufferSize > (INT64)FileSize)
-			read_size = (DWORD)((INT64)FileSize-Pointer+shift);
+		union { UINT64 u64FileSize; INT64 i64FileSize; } u;
+		u.i64FileSize = 0;
+		bool ok_size = vFile ? vFile->GetSize(&u.i64FileSize) : file.GetSize(u.u64FileSize);
 
-		Result = file.Read(Buffer, read_size, ReadSize);
+		if (ok_size && Pointer-shift+BufferSize > u.i64FileSize)
+			read_size = (DWORD)(u.i64FileSize-Pointer+shift);
+
+		Result = vFile ? vFile->Read(Buffer, read_size, ReadSize) : file.Read(Buffer, read_size, ReadSize);
 		if (Result)
 		{
 			if (ReadSize > (DWORD)shift)
 			{
 				BytesLeft = ReadSize - shift;
-				file.SetPointer(Pointer, nullptr, FILE_BEGIN);
+				if ( vFile )
+					vFile->SetPointer(Pointer, nullptr, FILE_BEGIN);
+				else
+					file.SetPointer(Pointer, nullptr, FILE_BEGIN);
 			}
 			else
 			{
@@ -183,8 +203,12 @@
 		}
 		else
 		{
-			if (shift)
-				file.SetPointer(Pointer, nullptr, FILE_BEGIN);
+			if (shift) {
+				if ( vFile )
+					vFile->SetPointer(Pointer, nullptr, FILE_BEGIN);
+				else
+					file.SetPointer(Pointer, nullptr, FILE_BEGIN);
+			}
 			ReadSize=0;
 			BytesLeft=0;
 		}
@@ -214,13 +238,13 @@
 bool CachedWrite::Write(LPCVOID Data, DWORD DataSize)
 {
 	bool Result=false;
-	bool SuccessFlush=true;
+	bool SuccessFlush = true;
 
-	if (Buffer)
+	if ( Buffer )
 	{
 		if (DataSize>FreeSize)
 		{
-			SuccessFlush=Flush();
+			SuccessFlush = Flush();
 		}
 
 		if(SuccessFlush)
@@ -228,8 +252,9 @@
 			if (DataSize>FreeSize)
 			{
 				DWORD WrittenSize=0;
+				bool ok_wr = file.Write(Data,DataSize,WrittenSize);
 
-				if (file.Write(Data, DataSize,WrittenSize) && DataSize==WrittenSize)
+				if (ok_wr && DataSize==WrittenSize)
 				{
 					Result=true;
 				}
@@ -253,8 +278,9 @@
 		if (!Flushed)
 		{
 			DWORD WrittenSize=0;
+			bool ok_wr = file.Write(Buffer,BufferSize-FreeSize,WrittenSize);
 
-			if (file.Write(Buffer, BufferSize-FreeSize, WrittenSize, nullptr) && BufferSize-FreeSize==WrittenSize)
+			if (ok_wr && BufferSize-FreeSize==WrittenSize)
 			{
 				Flushed=true;
 				FreeSize=BufferSize;
Index: filestr.hpp
===================================================================
--- filestr.hpp	(revision 6475)
+++ filestr.hpp	(working copy)
@@ -105,4 +105,7 @@
 		int GetUnicodeString(LPWSTR* DestStr, int& Length, bool bBigEndian);
 };
 
-bool GetFileFormat(File& file, UINT& nCodePage, bool* pSignatureFound = nullptr, bool bUseHeuristics = true);
\ No newline at end of file
+bool GetFileFormat(File& file, UINT& nCodePage, bool* pSignatureFound = nullptr, bool bUseHeuristics = true);
+
+class VFile;
+bool GetFileFormat(VFile *vf, UINT& nCodePage, bool* pSignatureFound = nullptr, bool bUseHeuristics = true);
Index: viewer.cpp
===================================================================
--- viewer.cpp	(revision 6475)
+++ viewer.cpp	(working copy)
@@ -158,16 +158,46 @@
 
 	memset(&vString, 0, sizeof(vString));
 	vString.lpData = new wchar_t[MAX_VIEWLINEB];
+
+	vFile = nullptr;
 }
 
+void Viewer::SetVFile( VFile *vf )
+{
+	vFile = vf;
+}
 
+bool Viewer::vOpened()
+{
+	return vFile || ViewFile.Opened();
+}
+
+bool Viewer::vClose()
+{
+	return vFile || ViewFile.Close();
+}
+
+bool Viewer::vOpen( const wchar_t *fname )
+{
+	return vFile || ViewFile.Open(fname,FILE_READ_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,nullptr,OPEN_EXISTING);
+}
+
+bool Viewer::vGetFileFormat(UINT& cp, bool bHeuristic)
+{
+	bool detect = vFile
+		? GetFileFormat(vFile, cp, &Signature, bHeuristic)
+		: GetFileFormat(ViewFile, cp, &Signature, bHeuristic
+	);
+	return detect;
+}
+
 Viewer::~Viewer()
 {
 	KeepInitParameters();
 
-	if (ViewFile.Opened())
+	if (vOpened())
 	{
-		ViewFile.Close();
+		vClose();
 
 		if (Opt.ViOpt.SavePos)
 		{
@@ -245,21 +275,43 @@
 	//InitHex=VM.Hex;
 }
 
+static bool IsDriveTypeFLOPPY( const string &strRoot ) // media have to be inserted...
+{
+	bool floppy = true; // returns true if can't open drive
 
+	string drive = HasPathPrefix(strRoot) ? strRoot : L"\\\\?\\" + strRoot;
+	DeleteEndSlash(drive, false);
+
+	HANDLE hDevice = ::CreateFileW(
+		drive.CPtr(),
+		GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, 0, nullptr
+	);
+	if ( INVALID_HANDLE_VALUE != hDevice )
+	{
+		DISK_GEOMETRY g;
+		DWORD dwOutBytes;
+		if ( DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL,0, &g,(DWORD)sizeof(g), &dwOutBytes,NULL)	)
+			floppy = ( g.MediaType != FixedMedia && g.MediaType != RemovableMedia );
+		CloseHandle(hDevice);
+	}
+	return floppy;
+}
+
 int Viewer::OpenFile(const wchar_t *Name,int warning)
 {
 	VM.CodePage=DefCodePage;
 	DefCodePage=CP_AUTODETECT;
 	OpenFailed=false;
 
-	ViewFile.Close();
+	vClose();
+
 	Reader.Clear();
 	vgetc_ready = lcache_ready = false;
 
 	SelectSize = -1; // ������� ��������
 	strFileName = Name;
 
-	if (Opt.OnlyEditorViewerUsed && !StrCmp(strFileName, L"-"))
+	if (!vFile && Opt.OnlyEditorViewerUsed && !StrCmp(strFileName, L"-"))
 	{
 		string strTempName;
 
@@ -290,10 +342,10 @@
 	}
 	else
 	{
-		ViewFile.Open(strFileName, FILE_READ_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, nullptr, OPEN_EXISTING);
+		vOpen(strFileName.CPtr());
 	}
 
-	if (!ViewFile.Opened())
+	if (!vOpened())
 	{
 		/* $ 04.07.2000 tran
 		   + 'warning' flag processing, in QuickView it is FALSE
@@ -305,12 +357,21 @@
 		OpenFailed=true;
 		return FALSE;
 	}
-	Reader.AdjustAlignment();
+	Reader.AdjustAlignment(vFile);
 
 	CodePageChangedByUser=FALSE;
 
-	ConvertNameToFull(strFileName,strFullFileName);
-	apiGetFindDataEx(strFileName, ViewFindData);
+	if ( vFile )
+	{
+		vFile->GetName(strFullFileName, true);
+		vFile->GetSize((PINT64)&ViewFindData.nFileSize);
+		vFile->GetUpdateTime(&ViewFindData.ftLastWriteTime);
+	}
+	else
+	{
+		ConvertNameToFull(strFileName,strFullFileName);
+		apiGetFindDataEx(strFileName, ViewFindData);
+	}
 	UINT CachedCodePage=0;
 
 	if (Opt.ViOpt.SavePos && !ReadStdin)
@@ -349,7 +410,7 @@
 
 		if (VM.CodePage == CP_AUTODETECT || IsUnicodeOrUtfCodePage(VM.CodePage))
 		{
-			Detect=GetFileFormat(ViewFile,CodePage,&Signature,Opt.ViOpt.AutoDetectCodePage!=0);
+			Detect = vGetFileFormat(CodePage, Opt.ViOpt.AutoDetectCodePage != 0);
 
 			// �������� ������������� ��� ��� ���������������� ������ �������
 			if (Detect)
@@ -377,7 +438,7 @@
 			CodePageChangedByUser=TRUE;
 		}
 
-		ViewFile.SetPointer(0, nullptr, FILE_BEGIN);
+		vseek(0, FILE_BEGIN);
 	}
 	SetFileSize();
 
@@ -393,19 +454,23 @@
 	bVE_READ_Sent = true;
 
 	last_update_check = GetTickCount();
-	string strRoot;
-	GetPathRoot(strFullFileName, strRoot);
-	int DriveType = FAR_GetDriveType(strRoot);
-	if (IsDriveTypeCDROM(DriveType))
-		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: 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
+	if ( vFile )
+		update_check_period = vFile->UpdateCheckPeriod();
+	else {
+		string strRoot;
+		GetPathRoot(strFullFileName, strRoot);
+		int DriveType = FAR_GetDriveType(strRoot);
+		if (IsDriveTypeCDROM(DriveType))
+			DriveType = DRIVE_CDROM;
+		switch (DriveType)
+		{                                                    // floppy: never, flash drive: 0.5 sec
+			case DRIVE_REMOVABLE: update_check_period = IsDriveTypeFLOPPY(strRoot) ? -1 : 500; break;
+			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;
@@ -431,7 +496,7 @@
 	int I,Y;
 	AdjustWidth();
 
-	if (!ViewFile.Opened())
+	if (!vOpened())
 	{
 		if (!strFileName.IsEmpty() && ((nMode == SHOW_RELOAD) || (nMode == SHOW_HEX)))
 		{
@@ -1128,9 +1193,9 @@
 		case MCODE_C_SELECTED:
 			return (__int64)(SelectSize >= 0 ?TRUE:FALSE);
 		case MCODE_C_EOF:
-			return (__int64)(LastPage || !ViewFile.Opened());
+			return (__int64)(LastPage || !vOpened());
 		case MCODE_C_BOF:
-			return (__int64)(!FilePos || !ViewFile.Opened());
+			return (__int64)(!FilePos || !vOpened());
 		case MCODE_V_VIEWERSTATE:
 		{
 			DWORD MacroViewerState=0;
@@ -1218,7 +1283,7 @@
 		case KEY_CTRLC:
 		case KEY_CTRLINS:  case KEY_CTRLNUMPAD0:
 		{
-			if (SelectSize >= 0 && ViewFile.Opened())
+			if (SelectSize >= 0 && vOpened())
 			{
 				wchar_t *SelData = (wchar_t*)xf_malloc((size_t)SelectSize+1);
 				if ( SelData )
@@ -1248,7 +1313,7 @@
 		}
 		case KEY_IDLE:
 		{
-			if (ViewFile.Opened() && update_check_period >= 0)
+			if (vOpened() && update_check_period >= 0)
 			{
 				DWORD now_ticks = GetTickCount();
 				if ((int)(now_ticks - last_update_check) < update_check_period)
@@ -1256,7 +1321,11 @@
 				last_update_check = now_ticks;
 
 				FAR_FIND_DATA_EX NewViewFindData;
-				if (!apiGetFindDataEx(strFullFileName, NewViewFindData))
+				bool ok = vFile
+					? vFile->GetSize((PINT64)&NewViewFindData.nFileSize) && vFile->GetUpdateTime(&NewViewFindData.ftLastWriteTime)
+					: apiGetFindDataEx(strFullFileName, NewViewFindData) != 0
+				;
+				if ( !ok )
 					return TRUE;
 
 				if (ViewFindData.ftLastWriteTime.dwLowDateTime!=NewViewFindData.ftLastWriteTime.dwLowDateTime
@@ -1267,7 +1336,8 @@
 					SetFileSize();
 
 					Reader.Clear(); // ���� ���� �� ��� ����?
-					ViewFile.FlushBuffers();
+					if ( !vFile )
+						ViewFile.FlushBuffers();
 					vseek(0, SEEK_CUR); // reset vgetc state
 					lcache_ready = false; // reset start-lines cache
 
@@ -1424,7 +1494,7 @@
 				if (nCodePage == (CP_AUTODETECT & 0xffff))
 				{
 					__int64 fpos = vtell();
-					bool detect = GetFileFormat(ViewFile,nCodePage,&Signature,true) && IsCodePageSupported(nCodePage);
+					bool detect = vGetFileFormat(nCodePage, true) && IsCodePageSupported(nCodePage);
 					vseek(fpos, SEEK_SET);
 					if (!detect)
 						nCodePage = Opt.ViOpt.AnsiCodePageAsDefault ? GetACP() : GetOEMCP();
@@ -1440,7 +1510,7 @@
 		}
 		case KEY_ALTF8:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				LastPage = 0;
 				GoTo();
@@ -1498,7 +1568,7 @@
 		}
 		case KEY_UP: case KEY_NUMPAD8: case KEY_SHIFTNUMPAD8:
 		{
-			if (FilePos>0 && ViewFile.Opened())
+			if (FilePos>0 && vOpened())
 			{
 				Up(1);	// LastPage = 0
 
@@ -1519,7 +1589,7 @@
 		}
 		case KEY_DOWN: case KEY_NUMPAD2:  case KEY_SHIFTNUMPAD2:
 		{
-			if (!LastPage && ViewFile.Opened())
+			if (!LastPage && vOpened())
 			{
 				if (VM.Hex)
 				{
@@ -1534,7 +1604,7 @@
 		}
 		case KEY_PGUP: case KEY_NUMPAD9: case KEY_SHIFTNUMPAD9: case KEY_CTRLUP:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				Up(Y2-Y1);
 				Show();
@@ -1544,7 +1614,7 @@
 		}
 		case KEY_PGDN: case KEY_NUMPAD3:  case KEY_SHIFTNUMPAD3: case KEY_CTRLDOWN:
 		{
-			if (LastPage || !ViewFile.Opened())
+			if (LastPage || !vOpened())
 				return TRUE;
 
 			FilePos = EndOfScreen(-1); // start of last screen line
@@ -1572,7 +1642,7 @@
 		}
 		case KEY_LEFT: case KEY_NUMPAD4: case KEY_SHIFTNUMPAD4:
 		{
-			if (LeftPos>0 && ViewFile.Opened())
+			if (LeftPos>0 && vOpened())
 			{
 				if (VM.Hex && LeftPos>80-Width)
 					LeftPos=Max(80-Width,1);
@@ -1585,7 +1655,7 @@
 		}
 		case KEY_RIGHT: case KEY_NUMPAD6: case KEY_SHIFTNUMPAD6:
 		{
-			if (LeftPos<MAX_VIEWLINE && ViewFile.Opened() && !VM.Hex && !VM.Wrap)
+			if (LeftPos<MAX_VIEWLINE && vOpened() && !VM.Hex && !VM.Wrap)
 			{
 				LeftPos++;
 				Show();
@@ -1595,7 +1665,7 @@
 		}
 		case KEY_CTRLLEFT: case KEY_CTRLNUMPAD4:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				if (VM.Hex)
 				{
@@ -1613,7 +1683,7 @@
 		}
 		case KEY_CTRLRIGHT: case KEY_CTRLNUMPAD6:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				if (VM.Hex)
 				{
@@ -1635,7 +1705,7 @@
 		case KEY_CTRLSHIFTLEFT:    case KEY_CTRLSHIFTNUMPAD4:
 
 			// ������� �� ����� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				LeftPos = 0;
 				Show();
@@ -1645,7 +1715,7 @@
 		case KEY_CTRLSHIFTRIGHT:     case KEY_CTRLSHIFTNUMPAD6:
 		{
 			// ������� �� ���� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				int I, Y, Len, MaxLen = 0;
 
@@ -1671,11 +1741,11 @@
 		case KEY_HOME:        case KEY_NUMPAD7:   case KEY_SHIFTNUMPAD7:
 
 			// ������� �� ����� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 				LeftPos=0;
 
 		case KEY_CTRLPGUP:    case KEY_CTRLNUMPAD9:
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				FilePos=0;
 				Show();
@@ -1686,12 +1756,12 @@
 		case KEY_END:         case KEY_NUMPAD1: case KEY_SHIFTNUMPAD1:
 
 			// ������� �� ���� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 				LeftPos=0;
 
 		case KEY_CTRLPGDN:    case KEY_CTRLNUMPAD3:
 
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				/* $ 15.08.2002 IS
 				   �� ������ ������, ���� ������� ������ �� �������� �������
@@ -1981,7 +2051,7 @@
 {
 	assert( nlines > 0 );
 
-	if (!ViewFile.Opened())
+	if (!vOpened())
 		return;
 
 	LastPage = 0;
@@ -2996,7 +3066,7 @@
 */
 void Viewer::Search(int Next,int FirstChar)
 {
-	if (!ViewFile.Opened() || (Next && strLastSearchStr.IsEmpty()))
+	if (!vOpened() || (Next && strLastSearchStr.IsEmpty()))
 		return;
 
 	string strSearchStr, strMsgStr;
@@ -3541,12 +3611,16 @@
 	}
 
 	vgetc_ready = false;
-	return ViewFile.SetPointer(Offset, nullptr, Whence);
+
+	return vFile
+		? vFile->SetPointer(Offset, nullptr, Whence)
+		: ViewFile.SetPointer(Offset, nullptr, Whence)
+	;
 }
 
 __int64 Viewer::vtell()
 {
-	__int64 Ptr = ViewFile.GetPointer();
+	__int64 Ptr = vFile ? vFile->GetPointer() : ViewFile.GetPointer();
 
 	if (vgetc_ready)
 		Ptr -= (vgetc_cb - vgetc_ib);
@@ -3559,7 +3633,7 @@
 	if (vgetc_ready && vgetc_ib < vgetc_cb)
 		return false;
 	else
-		return ViewFile.Eof();
+		return vFile ? vFile->Eof() : ViewFile.Eof();
 }
 
 bool Viewer::vgetc(wchar_t *pCh)
@@ -3567,7 +3641,7 @@
 	if (!vgetc_ready)
 		vgetc_cb = vgetc_ib = (int)(vgetc_composite = 0);
 
-	if (vgetc_cb - vgetc_ib < 4 && !ViewFile.Eof())
+	if (vgetc_cb - vgetc_ib < 4 && !(vFile ? vFile->Eof() : ViewFile.Eof()))
 	{
 		vgetc_cb -= vgetc_ib;
 		if (vgetc_cb && vgetc_ib)
@@ -3853,12 +3927,18 @@
 
 void Viewer::SetFileSize()
 {
-	if (!ViewFile.Opened())
+	if (!vOpened())
 		return;
 
-	UINT64 uFileSize=0; // BUGBUG, sign
-	ViewFile.GetSize(uFileSize);
-	FileSize=uFileSize;
+	union { UINT64 u64FileSize; INT64 i64FileSize; } u;
+	u.i64FileSize = 0;
+
+	if ( vFile )
+		vFile->GetSize(&u.i64FileSize);
+	else
+		ViewFile.GetSize(u.u64FileSize);
+
+	FileSize = u.i64FileSize;
 }
 
 
@@ -3874,7 +3954,7 @@
 //
 void Viewer::SelectText(const __int64 &match_pos,const __int64 &search_len, const DWORD flags)
 {
-	if (!ViewFile.Opened())
+	if (!vOpened())
 		return;
 
 	SelectPos = match_pos;
Index: plclass.cpp
===================================================================
--- plclass.cpp	(revision 6475)
+++ plclass.cpp	(working copy)
@@ -458,6 +458,7 @@
 	farRegExpControl,
 	farMacroControl,
 	farSettingsControl,
+	FarViewerVFile,
 };
 
 void CreatePluginStartupInfo(const Plugin* pPlugin, PluginStartupInfo *PSI, FarStandardFunctions *FSF)
Index: plugin.hpp
===================================================================
--- plugin.hpp	(revision 6475)
+++ plugin.hpp	(working copy)
@@ -866,6 +866,42 @@
     UINT CodePage
 );
 
+class VFile
+{
+public:
+	virtual ~VFile() {}
+
+	enum VFile_Versions
+	{ VFile_Version_Base    = 0x100 // 1.00
+	, VFile_Version_Current = 0x100
+	};
+	virtual int Version() =0;
+
+	virtual bool GetName( string& fname, bool full=false ) =0;
+
+	virtual bool SetPointer( INT64 off, PINT64 ppos, int whence ) =0;
+	virtual INT64 GetPointer() =0;
+	virtual bool Eof() =0;
+
+	virtual bool GetSize( INT64 *fsize ) =0;
+	virtual bool GetUpdateTime( FILETIME *ftime ) =0;
+	virtual int UpdateCheckPeriod() =0;
+
+	virtual bool Read( void *buff, DWORD nb, DWORD& nr ) =0;
+	virtual bool Write( const void *buff, DWORD nb, DWORD& nw ) =0;
+};
+
+typedef int (WINAPI *FARAPIVIEWER_VFILE)(
+	VFile *vFile,
+	const wchar_t *Title,
+	int X1,
+	int Y1,
+	int X2,
+	int Y2,
+	VIEWER_FLAGS Flags,
+	UINT CodePage
+);
+
 typedef unsigned __int64 EDITOR_FLAGS;
 static const EDITOR_FLAGS
 	EF_NONMODAL              = 0x0000000000000001ULL,
@@ -2154,6 +2190,8 @@
 	FARAPIREGEXPCONTROL    RegExpControl;
 	FARAPIMACROCONTROL     MacroControl;
 	FARAPISETTINGSCONTROL  SettingsControl;
+
+	FARAPIVIEWER_VFILE     ViewerVF;
 };
 
 
Index: plugapi.hpp
===================================================================
--- plugapi.hpp	(revision 6475)
+++ plugapi.hpp	(working copy)
@@ -89,11 +89,15 @@
 int WINAPI FarGetDirList(const wchar_t *Dir, PluginPanelItem **pPanelItem, size_t *pItemsNumber);
 void WINAPI FarFreeDirList(PluginPanelItem *PanelItem, size_t nItemsNumber);
 
-int WINAPI FarViewer(const wchar_t *FileName,const wchar_t *Title,
+int WINAPI FarViewer(const wchar_t *FileName, const wchar_t *Title,
                      int X1,int Y1,int X2,int Y2,unsigned __int64 Flags, UINT CodePage);
+int WINAPI FarViewerVFile(VFile *vFile, const wchar_t *Title,
+	int X1,int Y1,int X2,int Y2,unsigned __int64 Flags, UINT CodePage);
+
 int WINAPI FarEditor(const wchar_t *FileName,const wchar_t *Title,
                      int X1,int Y1,int X2, int Y2,unsigned __int64 Flags,
                      int StartLine,int StartChar, UINT CodePage);
+
 void WINAPI FarText(int X,int Y,const FarColor* Color,const wchar_t *Str);
 
 INT_PTR WINAPI FarEditorControl(int EditorID, EDITOR_CONTROL_COMMANDS Command, int Param1, void* Param2);
Virtual_Viewer2.diff (29,038 bytes)   

2useven10

2011-07-22 13:01

developer   bugnote:0007293

убираем костыль...
VF_VFILE - удален,
VFile перенесен в plugin.hpp,
в PluginStartupInfo добавлен FarViewerVFile().

samlyukov

2011-07-22 13:45

reporter   bugnote:0007295

тема перекликается с http://bugs.farmanager.com/view.php?id=156

zg

2011-07-24 09:01

developer   bugnote:0007305

> VFile перенесен в plugin.hpp
последствия:
1. плагины можно писать только на c++.
2. в общем случае плагины можно собирать только тем же компилятором, что собран фар.

2useven10

2011-07-24 12:40

developer   bugnote:0007306

1. да, но ограничение спокойно понижается до 'плагины использующие VFile' можно писать только на C++ (интерфейс отселить, вместо него просто class VFile *, или дажк void *, если потребуется).
2. с учётом 1. - сильно преувеличено

Вообще всё это о том, что 'можно, если будет востребовано'...
Если нет, значит нет.

zg

2011-07-24 13:58

developer   bugnote:0007307

> 'плагины использующие VFile' можно писать только на C++
нет в этом никакой необходимости.
> 2. с учётом 1. - сильно преувеличено
преувеличено в чём? бинарной совместимости представления класса не гарантируется даже между версиями компилятора.

vskirdin

2011-07-24 16:38

administrator   bugnote:0007308

Я так думаю, что вместо "class VFile" нужен "struct VFile", в котором, вместо абстракций, будут ссылки на функции (как в FSF)...
...тогда ограничения на C++ не будет.
не?

2useven10

2011-08-27 08:22

developer  

Virtual-Viewer-plain_C.diff (37,297 bytes)   
Index: far.vcxproj
===================================================================
--- far.vcxproj	(revision 6635)
+++ far.vcxproj	(working copy)
@@ -660,6 +660,7 @@
     <ClCompile Include="udlist.cpp" />
     <ClCompile Include="UnicodeString.cpp" />
     <ClCompile Include="usermenu.cpp" />
+    <ClCompile Include="vFile.cpp" />
     <ClCompile Include="viewer.cpp" />
     <ClCompile Include="vmenu.cpp" />
     <ClCompile Include="window.cpp" />
@@ -1078,6 +1079,7 @@
     <ClInclude Include="udlist.hpp" />
     <ClInclude Include="UnicodeString.hpp" />
     <ClInclude Include="usermenu.hpp" />
+    <ClInclude Include="vFile.hpp" />
     <ClInclude Include="viewer.hpp" />
     <ClInclude Include="vmenu.hpp" />
     <ClInclude Include="wakeful.hpp" />
Index: filestr.cpp
===================================================================
--- filestr.cpp	(revision 6635)
+++ filestr.cpp	(working copy)
@@ -40,6 +40,7 @@
 #include "config.hpp"
 #include "configdb.hpp"
 #include "codepage.hpp"
+#include "vFile.hpp"
 
 const size_t DELTA = 1024;
 const size_t ReadBufCount = 0x2000;
@@ -907,34 +908,40 @@
 
 bool GetFileFormat(File& file, UINT& nCodePage, bool* pSignatureFound, bool bUseHeuristics)
 {
+	RegularFile vf(file);
+	return GetFileFormat(&vf, nCodePage, pSignatureFound, bUseHeuristics);
+}
+
+bool GetFileFormat(VFile *vf, UINT& nCodePage, bool* pSignatureFound, bool bUseHeuristics)
+{
 	DWORD dwTemp=0;
 	bool bSignatureFound = false;
 	bool bDetect=false;
 
 	DWORD Readed = 0;
-	if (file.Read(&dwTemp, sizeof(dwTemp), Readed) && Readed > 1 ) // minimum signature size is 2 bytes
+	if (vf->Read(&dwTemp, sizeof(dwTemp), Readed) && Readed > 1 ) // minimum signature size is 2 bytes
 	{
 		if (LOWORD(dwTemp) == SIGN_UNICODE)
 		{
 			nCodePage = CP_UNICODE;
-			file.SetPointer(2, nullptr, FILE_BEGIN);
+			vf->SetPointer(2, nullptr, FILE_BEGIN);
 			bSignatureFound = true;
 		}
 		else if (LOWORD(dwTemp) == SIGN_REVERSEBOM)
 		{
 			nCodePage = CP_REVERSEBOM;
-			file.SetPointer(2, nullptr, FILE_BEGIN);
+			vf->SetPointer(2, nullptr, FILE_BEGIN);
 			bSignatureFound = true;
 		}
 		else if ((dwTemp & 0x00FFFFFF) == SIGN_UTF8)
 		{
 			nCodePage = CP_UTF8;
-			file.SetPointer(3, nullptr, FILE_BEGIN);
+			vf->SetPointer(3, nullptr, FILE_BEGIN);
 			bSignatureFound = true;
 		}
 		else
 		{
-			file.SetPointer(0, nullptr, FILE_BEGIN);
+			vf->SetPointer(0, nullptr, FILE_BEGIN);
 		}
 	}
 
@@ -944,12 +951,12 @@
 	}
 	else if (bUseHeuristics)
 	{
-		file.SetPointer(0, nullptr, FILE_BEGIN);
+		vf->SetPointer(0, nullptr, FILE_BEGIN);
 		DWORD Size=0x8000; // BUGBUG. TODO: configurable
 		LPVOID Buffer=xf_malloc(Size);
 		DWORD ReadSize = 0;
-		bool ReadResult = file.Read(Buffer, Size, ReadSize);
-		file.SetPointer(0, nullptr, FILE_BEGIN);
+		bool ReadResult = vf->Read(Buffer, Size, ReadSize);
+		vf->SetPointer(0, nullptr, FILE_BEGIN);
 
 		if (ReadResult && ReadSize)
 		{
Index: plugapi.cpp
===================================================================
--- plugapi.cpp	(revision 6635)
+++ plugapi.cpp	(working copy)
@@ -76,6 +76,7 @@
 #include "plugsettings.hpp"
 #include "farversion.hpp"
 #include "mix.hpp"
+#include "vFile.hpp"
 
 wchar_t *WINAPI FarItoa(int value, wchar_t *string, int radix)
 {
@@ -1799,12 +1800,26 @@
 	xf_free(PanelItem);
 }
 
-int WINAPI FarViewer(const wchar_t *FileName,const wchar_t *Title,
+static int far_viewer(const wchar_t *FileName, struct SVFile *svf, const wchar_t *Title,
                      int X1,int Y1,int X2, int Y2,unsigned __int64 Flags, UINT CodePage)
 {
 	if (FrameManager->ManagerIsDown())
 		return FALSE;
 
+	bool bDirect = (0 != (Flags & VF_DIRECT_VFILE));
+	ProxySVFile proxy_vf(bDirect || FileName ? nullptr : svf);
+	VFile *vf = nullptr;
+	string fname;
+
+	if ( !FileName && svf )
+	{
+		vf = bDirect ? reinterpret_cast<VFile *>(svf) : &proxy_vf;
+		const wchar_t *fnm = vf->GetName(false);
+		if ( fnm )
+			fname = fnm;
+		FileName = fname.CPtr();
+	}
+
 	class ConsoleTitle ct;
 	int DisableHistory=(Flags & VF_DISABLEHISTORY)?TRUE:FALSE;
 
@@ -1822,6 +1837,8 @@
 		if (!Viewer)
 			return FALSE;
 
+		Viewer->SetVFile(vf);
+
 		/* $ 14.06.2002 IS
 		   ��������� VF_DELETEONLYFILEONCLOSE - ���� ���� ����� ����� ������
 		   ��������� �� �������� � VF_DELETEONCLOSE
@@ -1856,6 +1873,8 @@
 		FrameManager->ExecuteModal();
 		FrameManager->ExitModalEV();
 
+		Viewer.SetVFile(vf);
+
 		/* $ 14.06.2002 IS
 		   ��������� VF_DELETEONLYFILEONCLOSE - ���� ���� ����� ����� ������
 		   ��������� �� �������� � VF_DELETEONCLOSE
@@ -1874,7 +1893,18 @@
 	return TRUE;
 }
 
+int WINAPI FarViewer(const wchar_t *FileName, const wchar_t *Title,
+	int X1,int Y1,int X2, int Y2,unsigned __int64 Flags, UINT CodePage)
+{
+	return far_viewer(FileName, nullptr, Title, X1,Y1, X2,Y2, Flags, CodePage);
+}
 
+int WINAPI FarViewerVFile(struct SVFile *svf, const wchar_t *Title,
+	int X1,int Y1,int X2, int Y2,unsigned __int64 Flags, UINT CodePage)
+{
+	return far_viewer(nullptr, svf, Title, X1,Y1, X2,Y2, Flags, CodePage);
+}
+
 int WINAPI FarEditor(
     const wchar_t *FileName,
     const wchar_t *Title,
Index: cache.hpp
===================================================================
--- cache.hpp	(revision 6635)
+++ cache.hpp	(working copy)
@@ -32,12 +32,14 @@
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+class VFile;
+
 class CachedRead
 {
 public:
 	CachedRead(File& file, DWORD buffer_size=0);
 	~CachedRead();
-	bool AdjustAlignment(); // file have to be opened already
+	bool AdjustAlignment(VFile *vf=nullptr); // file have to be opened already
 	bool Read(LPVOID Data, DWORD DataSize, LPDWORD BytesRead);
 	bool FillBuffer();
 	bool Unread(DWORD BytesUnread);
@@ -52,6 +54,7 @@
 	INT64 LastPtr;
 	DWORD BufferSize; // = 2*k*Alignment (k >= 2)
 	int   Alignment;  //
+	VFile *vFile;
 };
 
 
@@ -69,5 +72,4 @@
 	enum {BufferSize=0x10000};
 	DWORD FreeSize;
 	bool Flushed;
-
 };
Index: vFile.hpp
===================================================================
--- vFile.hpp	(revision 0)
+++ vFile.hpp	(revision 0)
@@ -0,0 +1,148 @@
+#pragma once
+#ifndef __VFILE_HPP__
+#define __VFILE_HPP__
+
+#include "plugin.hpp"
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
+class VFile
+{
+public:
+	virtual ~VFile() {};
+
+	virtual int   Version() =0;
+
+	virtual const wchar_t *GetName( bool full=false ) =0;
+
+	virtual bool  SetPointer( INT64 off, PINT64 ppos, int whence ) =0;
+	virtual INT64 GetPointer() =0;
+	virtual bool  Eof() =0;
+
+	virtual bool  GetSize( INT64 *fsize ) =0;
+	virtual bool  GetUpdateTime( FILETIME *ftime ) =0;
+	virtual int   UpdateCheckPeriod() =0;
+
+	virtual bool  Read( void *buff, DWORD nb, DWORD& nr ) =0;
+	virtual bool  Write( const void *buff, DWORD nb, DWORD& nw ) =0;
+};
+
+//---------------------------------------------------------------------------
+
+extern bool VFile2SVFile( VFile *vFile, struct SVFile& svFile );
+
+//---------------------------------------------------------------------------
+
+class ProxySVFile : public VFile
+{
+private:
+	struct SVFile *proxy_;
+	void *context_;
+
+public:
+	ProxySVFile( struct SVFile *proxy ) : proxy_(proxy) {
+		context_ = proxy ? proxy->ctx : nullptr;
+		//TODO: check version
+	}
+	~ProxySVFile() {}
+
+public:
+	virtual int Version() {
+		return context_ ? proxy_->Version(context_) : 0x00;
+	}
+
+	virtual const wchar_t *GetName( bool full ) {
+		return context_ ? proxy_->GetName(context_, full ? TRUE : FALSE) : nullptr;
+	}
+
+	virtual bool SetPointer( INT64 off, PINT64 ppos, int whence ) {
+		return context_ ? proxy_->SetPointer(context_, off, ppos, whence) != FALSE : false;
+	}
+
+	virtual INT64 GetPointer() {
+		return context_ ? proxy_->GetPointer(context_) : -1;
+	}
+
+	virtual bool Eof() {
+		return context_ ? proxy_->Eof(context_) != FALSE : true;
+	}
+
+	virtual bool GetSize( INT64 *fsize ) {
+		return context_ ? proxy_->GetSize(context_, fsize) != FALSE : false;
+	}
+
+	virtual bool GetUpdateTime( FILETIME *ftime ) {
+		return context_ ? proxy_->GetUpdateTime(context_, ftime) != FALSE: false;
+	}
+
+	virtual int UpdateCheckPeriod() {
+		return context_ ? proxy_->UpdateCheckPeriod(context_) : -1;
+	}
+
+	virtual bool Read( void *buff, DWORD nb, DWORD& nr ) {
+		return context_ ? proxy_->Read(context_, buff, nb, &nr) != FALSE: false;
+	}
+
+	virtual bool Write( const void *buff, DWORD nb, DWORD& nw ) {
+		return context_ ? proxy_->Write(context_, buff, nb, &nw) != FALSE : false;
+	}
+};
+
+//---------------------------------------------------------------------------
+
+class RegularFile : public VFile
+{
+private:
+	File&  _file;
+	string _fnam;
+	string _full;
+	int  _ucheck;
+
+public:
+	RegularFile(File &file, int ucheck = -1) : _file(file), _ucheck(ucheck) {}
+	~RegularFile() {}
+
+	virtual int Version() { return VFile_Version_Current; }
+
+	virtual const wchar_t *GetName( bool full )
+	{
+		if ( !_file.Opened() )
+			return nullptr;
+
+		if ( !full )
+			return _fnam.CPtr();
+
+		ConvertNameToFull( _fnam.CPtr(), _full);
+		return _full.CPtr();
+	}
+
+	virtual bool SetPointer( INT64 off, PINT64 ppos, int whence )
+	{ return _file.SetPointer(off,ppos,(DWORD)whence); }
+
+	virtual INT64 GetPointer() { return _file.GetPointer(); }
+
+	virtual bool Eof() { return _file.Eof(); } 
+
+	virtual bool GetSize( INT64 *fsize )
+	{
+		UINT64 usz=0;
+		bool r = _file.GetSize(usz);
+		*fsize=(UINT64)usz;
+		return r;
+	}
+	
+	virtual bool GetUpdateTime( FILETIME *ftime )
+	{ return _file.GetTime(nullptr, nullptr, ftime, nullptr); }
+
+	virtual int UpdateCheckPeriod() { return _ucheck; }
+
+	virtual bool Read( void *buff, DWORD nb, DWORD& nr )
+	{ return _file.Read( buff, nb, nr, nullptr); }
+
+	virtual bool Write( const void *buff, DWORD nb, DWORD& nw )
+	{ return _file.Write( buff, nb, nw, nullptr); }
+};	
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+#endif /* __VFILE_HPP__ */
Index: fileview.hpp
===================================================================
--- fileview.hpp	(revision 6635)
+++ fileview.hpp	(working copy)
@@ -104,4 +104,6 @@
 		__int64 GetViewFilePos() const;
 		void ShowStatus();
 		int GetId(void) const { return View.ViewerID; };
+
+		void SetVFile( VFile *vf ) { View.SetVFile(vf); }
 };
Index: viewer.hpp
===================================================================
--- viewer.hpp	(revision 6635)
+++ viewer.hpp	(working copy)
@@ -174,6 +174,8 @@
 		int  vgetc_ib;
 		wchar_t vgetc_composite;
 
+		VFile *vFile;
+
 	private:
 		virtual void DisplayObject();
 
@@ -220,6 +222,12 @@
 		bool veof();
 		wchar_t vgetc_prev();
 
+		bool vOpened();
+		bool vClose();
+		bool vOpen( const wchar_t *fname );
+
+		bool vGetFileFormat(UINT& cp, bool bHeuristic);
+
 		void SetFileSize();
 		int GetStrBytesNum(const wchar_t *Str, int Length);
 
@@ -297,4 +305,6 @@
 		int ProcessTypeWrapMode(int newMode, bool isRedraw=TRUE);
 
 		void SearchTextTransform(UnicodeString &to, const wchar_t *from, bool hex2text, int &pos);
+
+		void SetVFile( VFile *vf );
 };
Index: cache.cpp
===================================================================
--- cache.cpp	(revision 6635)
+++ cache.cpp	(working copy)
@@ -34,17 +34,18 @@
 #pragma hdrstop
 
 #include "cache.hpp"
+#include "vFile.hpp"
 
 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));
+	vFile = nullptr;
 }
 
 CachedRead::~CachedRead()
@@ -52,15 +53,17 @@
 	xf_free(Buffer);
 }
 
-bool CachedRead::AdjustAlignment()
+bool CachedRead::AdjustAlignment( VFile *vf )
 {
-	if (!file.Opened())
+	vFile = vf;
+
+	if ( !vFile && !file.Opened() )
 		return false;
 
 	DWORD ret, buff_size = BufferSize;
 	DISK_GEOMETRY g;
 
-	if (file.IoControl(IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr,0, &g,(DWORD)sizeof(g), &ret,nullptr))
+	if (!vFile && file.IoControl(IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr,0, &g,(DWORD)sizeof(g), &ret,nullptr))
 	{
 		if (g.BytesPerSector > 512 && g.BytesPerSector <= 256*1024)
 		{
@@ -90,7 +93,7 @@
 
 bool CachedRead::Read(LPVOID Data, DWORD DataSize, LPDWORD BytesRead)
 {
-	INT64 Ptr = file.GetPointer();
+	INT64 Ptr = vFile ? vFile->GetPointer() : file.GetPointer();
 
 	if(Ptr!=LastPtr)
 	{
@@ -121,18 +124,22 @@
 
 			Result=true;
 
-			DWORD Actual=Min(BytesLeft, DataSize);
+			DWORD Actual = Min(BytesLeft, DataSize);
 			memcpy(Data, &Buffer[ReadSize-BytesLeft], Actual);
-			Data=((LPBYTE)Data)+Actual;
-			BytesLeft-=Actual;
-			file.SetPointer(Actual, &LastPtr, FILE_CURRENT);
-			*BytesRead+=Actual;
-			DataSize-=Actual;
+			Data = ((LPBYTE)Data)+Actual;
+			BytesLeft -= Actual;
+			if ( vFile )
+				vFile->SetPointer(Actual, &LastPtr, FILE_CURRENT);
+			else
+				file.SetPointer(Actual, &LastPtr, FILE_CURRENT);
+
+			*BytesRead += Actual;
+			DataSize -= Actual;
 		}
 	}
 	else
 	{
-		Result = file.Read(Data, DataSize, *BytesRead);
+		Result = vFile ? vFile->Read(Data, DataSize, *BytesRead) : file.Read(Data, DataSize, *BytesRead);
 	}
 	return Result;
 }
@@ -143,7 +150,10 @@
 	{
 		BytesLeft += BytesUnread;
 		__int64 off = BytesUnread;
-		file.SetPointer(-off, &LastPtr, FILE_CURRENT);
+		if ( vFile)
+			vFile->SetPointer(-off, &LastPtr, FILE_CURRENT);
+		else
+			file.SetPointer(-off, &LastPtr, FILE_CURRENT);
 		return true;
 	}
 	return false;
@@ -152,29 +162,39 @@
 bool CachedRead::FillBuffer()
 {
 	bool Result=false;
-	if (!file.Eof())
+	if ( (vFile && !vFile->Eof()) || (!vFile && !file.Eof()) )
 	{
-		INT64 Pointer = file.GetPointer();
+		INT64 Pointer = vFile ? vFile->GetPointer() : file.GetPointer();
 
 		int shift = (int)(Pointer % Alignment);
 		if (Pointer-shift > BufferSize/2)
 			shift += BufferSize/2;
 
-		if (shift)
-			file.SetPointer(-shift, nullptr, FILE_CURRENT);
+		if ( shift ) {
+			if ( vFile )
+				vFile->SetPointer(-shift, nullptr, FILE_CURRENT);
+			else
+				file.SetPointer(-shift, nullptr, FILE_CURRENT);
+		}
 
 		DWORD read_size = BufferSize;
-		UINT64 FileSize = 0;
-		if (file.GetSize(FileSize) && Pointer-shift+BufferSize > (INT64)FileSize)
-			read_size = (DWORD)((INT64)FileSize-Pointer+shift);
+		union { UINT64 u64FileSize; INT64 i64FileSize; } u;
+		u.i64FileSize = 0;
+		bool ok_size = vFile ? vFile->GetSize(&u.i64FileSize) : file.GetSize(u.u64FileSize);
 
-		Result = file.Read(Buffer, read_size, ReadSize);
+		if (ok_size && Pointer-shift+BufferSize > u.i64FileSize)
+			read_size = (DWORD)(u.i64FileSize-Pointer+shift);
+
+		Result = vFile ? vFile->Read(Buffer, read_size, ReadSize) : file.Read(Buffer, read_size, ReadSize);
 		if (Result)
 		{
 			if (ReadSize > (DWORD)shift)
 			{
 				BytesLeft = ReadSize - shift;
-				file.SetPointer(Pointer, nullptr, FILE_BEGIN);
+				if ( vFile )
+					vFile->SetPointer(Pointer, nullptr, FILE_BEGIN);
+				else
+					file.SetPointer(Pointer, nullptr, FILE_BEGIN);
 			}
 			else
 			{
@@ -183,8 +203,12 @@
 		}
 		else
 		{
-			if (shift)
-				file.SetPointer(Pointer, nullptr, FILE_BEGIN);
+			if (shift) {
+				if ( vFile )
+					vFile->SetPointer(Pointer, nullptr, FILE_BEGIN);
+				else
+					file.SetPointer(Pointer, nullptr, FILE_BEGIN);
+			}
 			ReadSize=0;
 			BytesLeft=0;
 		}
@@ -214,13 +238,13 @@
 bool CachedWrite::Write(LPCVOID Data, DWORD DataSize)
 {
 	bool Result=false;
-	bool SuccessFlush=true;
+	bool SuccessFlush = true;
 
-	if (Buffer)
+	if ( Buffer )
 	{
 		if (DataSize>FreeSize)
 		{
-			SuccessFlush=Flush();
+			SuccessFlush = Flush();
 		}
 
 		if(SuccessFlush)
@@ -228,8 +252,9 @@
 			if (DataSize>FreeSize)
 			{
 				DWORD WrittenSize=0;
+				bool ok_wr = file.Write(Data,DataSize,WrittenSize);
 
-				if (file.Write(Data, DataSize,WrittenSize) && DataSize==WrittenSize)
+				if (ok_wr && DataSize==WrittenSize)
 				{
 					Result=true;
 				}
@@ -253,8 +278,9 @@
 		if (!Flushed)
 		{
 			DWORD WrittenSize=0;
+			bool ok_wr = file.Write(Buffer,BufferSize-FreeSize,WrittenSize);
 
-			if (file.Write(Buffer, BufferSize-FreeSize, WrittenSize, nullptr) && BufferSize-FreeSize==WrittenSize)
+			if (ok_wr && BufferSize-FreeSize==WrittenSize)
 			{
 				Flushed=true;
 				FreeSize=BufferSize;
Index: vFile.cpp
===================================================================
--- vFile.cpp	(revision 0)
+++ vFile.cpp	(revision 0)
@@ -0,0 +1,81 @@
+#include "headers.hpp"
+#pragma hdrstop
+
+#include "vFile.hpp"
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
+static int WINAPI svfVersion(void* ctx)
+{
+	return ((VFile *)ctx)->Version();
+}
+
+static const wchar_t* WINAPI svfGetName(void* ctx, BOOL full)
+{
+	return ((VFile *)ctx)->GetName(full != FALSE);
+}
+
+static BOOL WINAPI svfSetPointer(void* ctx, INT64 off, PINT64 ppos, int whence)
+{
+	return ((VFile *)ctx)->SetPointer(off, ppos, whence);
+}
+
+static INT64 WINAPI svfGetPointer(void* ctx)
+{
+	return ((VFile *)ctx)->GetPointer();
+}
+
+static BOOL WINAPI svfEof(void* ctx)
+{
+	return ((VFile *)ctx)->Eof();
+}
+
+static BOOL WINAPI svfGetSize(void* ctx, INT64 *fsize)
+{
+	return ((VFile *)ctx)->GetSize(fsize);
+}
+
+static BOOL WINAPI svfGetUpdateTime(void* ctx, FILETIME *ftime)
+{
+	return ((VFile *)ctx)->GetUpdateTime(ftime);
+}
+
+static int WINAPI svfUpdateCheckPeriod(void* ctx)
+{
+	return ((VFile *)ctx)->UpdateCheckPeriod();
+}
+
+static BOOL WINAPI svfRead(void* ctx, void *buff, DWORD nb, DWORD* nr)
+{
+	return ((VFile *)ctx)->Read(buff, nb, *nr);
+}
+
+static BOOL WINAPI svfWrite(void* ctx, const void *buff, DWORD nb, DWORD* nw)
+{
+	return ((VFile *)ctx)->Write(buff, nb, *nw);
+}
+
+//---------------------------------------------------------------------------
+
+bool VFile2SVFile( VFile *vFile, struct SVFile& svFile )
+{
+	if ( !vFile )
+		return false;
+
+	svFile.ctx = vFile;
+	svFile.Version = svfVersion;
+	svFile.GetName = svfGetName;
+	svFile.SetPointer = svfSetPointer;
+	svFile.GetPointer = svfGetPointer;
+	svFile.Eof = svfEof;
+	svFile.GetSize = svfGetSize;
+	svFile.GetUpdateTime = svfGetUpdateTime;
+	svFile.UpdateCheckPeriod = svfUpdateCheckPeriod;
+	svFile.Read = svfRead;
+	svFile.Write = svfWrite;	
+
+	return true;
+}
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
Index: filestr.hpp
===================================================================
--- filestr.hpp	(revision 6635)
+++ filestr.hpp	(working copy)
@@ -105,4 +105,7 @@
 		int GetUnicodeString(LPWSTR* DestStr, int& Length, bool bBigEndian);
 };
 
-bool GetFileFormat(File& file, UINT& nCodePage, bool* pSignatureFound = nullptr, bool bUseHeuristics = true);
\ No newline at end of file
+bool GetFileFormat(File& file, UINT& nCodePage, bool* pSignatureFound = nullptr, bool bUseHeuristics = true);
+
+class VFile;
+bool GetFileFormat(VFile *vf, UINT& nCodePage, bool* pSignatureFound = nullptr, bool bUseHeuristics = true);
Index: plclass.cpp
===================================================================
--- plclass.cpp	(revision 6635)
+++ plclass.cpp	(working copy)
@@ -460,6 +460,7 @@
 	farRegExpControl,
 	farMacroControl,
 	farSettingsControl,
+	FarViewerVFile,
 };
 
 void CreatePluginStartupInfo(const Plugin* pPlugin, PluginStartupInfo *PSI, FarStandardFunctions *FSF)
Index: viewer.cpp
===================================================================
--- viewer.cpp	(revision 6635)
+++ viewer.cpp	(working copy)
@@ -67,6 +67,7 @@
 #include "wakeful.hpp"
 #include "RegExp.hpp"
 #include "palette.hpp"
+#include "vFile.hpp"
 
 static void PR_ViewerSearchMsg();
 static void ViewerSearchMsg(const wchar_t *name, int percent, int search_hex);
@@ -157,16 +158,46 @@
 
 	ClearStruct(vString);
 	vString.lpData = new wchar_t[MAX_VIEWLINEB];
+
+	vFile = nullptr;
 }
 
+void Viewer::SetVFile( VFile *vf )
+{
+	vFile = vf;
+}
 
+bool Viewer::vOpened()
+{
+	return vFile || ViewFile.Opened();
+}
+
+bool Viewer::vClose()
+{
+	return vFile || ViewFile.Close();
+}
+
+bool Viewer::vOpen( const wchar_t *fname )
+{
+	return vFile || ViewFile.Open(fname,FILE_READ_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,nullptr,OPEN_EXISTING);
+}
+
+bool Viewer::vGetFileFormat(UINT& cp, bool bHeuristic)
+{
+	bool detect = vFile
+		? GetFileFormat(vFile, cp, &Signature, bHeuristic)
+		: GetFileFormat(ViewFile, cp, &Signature, bHeuristic
+	);
+	return detect;
+}
+
 Viewer::~Viewer()
 {
 	KeepInitParameters();
 
-	if (ViewFile.Opened())
+	if (vOpened())
 	{
-		ViewFile.Close();
+		vClose();
 
 		if (Opt.ViOpt.SavePos)
 		{
@@ -251,14 +282,14 @@
 	DefCodePage=CP_AUTODETECT;
 	OpenFailed=false;
 
-	ViewFile.Close();
+	vClose();
 	Reader.Clear();
 	vgetc_ready = lcache_ready = false;
 
 	SelectSize = -1; // ������� ��������
 	strFileName = Name;
 
-	if (Opt.OnlyEditorViewerUsed && !StrCmp(strFileName, L"-"))
+	if (!vFile && Opt.OnlyEditorViewerUsed && !StrCmp(strFileName, L"-"))
 	{
 		string strTempName;
 
@@ -289,10 +320,10 @@
 	}
 	else
 	{
-		ViewFile.Open(strFileName, FILE_READ_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, nullptr, OPEN_EXISTING);
+		vOpen(strFileName.CPtr());
 	}
 
-	if (!ViewFile.Opened())
+	if (!vOpened())
 	{
 		/* $ 04.07.2000 tran
 		   + 'warning' flag processing, in QuickView it is FALSE
@@ -304,12 +335,23 @@
 		OpenFailed=true;
 		return FALSE;
 	}
-	Reader.AdjustAlignment();
+	Reader.AdjustAlignment(vFile);
 
 	CodePageChangedByUser=FALSE;
 
-	ConvertNameToFull(strFileName,strFullFileName);
-	apiGetFindDataEx(strFileName, ViewFindData);
+	if ( vFile )
+	{
+		const wchar_t *full_fnm = vFile->GetName(true);
+		if ( full_fnm )
+			strFullFileName = full_fnm;
+		vFile->GetSize((PINT64)&ViewFindData.nFileSize);
+		vFile->GetUpdateTime(&ViewFindData.ftLastWriteTime);
+	}
+	else
+	{
+		ConvertNameToFull(strFileName,strFullFileName);
+		apiGetFindDataEx(strFileName, ViewFindData);
+	}
 	UINT CachedCodePage=0;
 
 	if (Opt.ViOpt.SavePos && !ReadStdin)
@@ -348,7 +390,7 @@
 
 		if (VM.CodePage == CP_AUTODETECT || IsUnicodeOrUtfCodePage(VM.CodePage))
 		{
-			Detect=GetFileFormat(ViewFile,CodePage,&Signature,Opt.ViOpt.AutoDetectCodePage!=0);
+			Detect = vGetFileFormat(CodePage, Opt.ViOpt.AutoDetectCodePage != 0);
 
 			// �������� ������������� ��� ��� ���������������� ������ �������
 			if (Detect)
@@ -376,7 +418,7 @@
 			CodePageChangedByUser=TRUE;
 		}
 
-		ViewFile.SetPointer(0, nullptr, FILE_BEGIN);
+		vseek(0, FILE_BEGIN);
 	}
 	SetFileSize();
 
@@ -392,19 +434,23 @@
 	bVE_READ_Sent = true;
 
 	last_update_check = GetTickCount();
-	string strRoot;
-	GetPathRoot(strFullFileName, strRoot);
-	int DriveType = FAR_GetDriveType(strRoot);
-	if (IsDriveTypeCDROM(DriveType))
-		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: 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
+	if ( vFile )
+		update_check_period = vFile->UpdateCheckPeriod();
+	else {
+		string strRoot;
+		GetPathRoot(strFullFileName, strRoot);
+		int DriveType = FAR_GetDriveType(strRoot);
+		if (IsDriveTypeCDROM(DriveType))
+			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: 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;
@@ -430,7 +476,7 @@
 	int I,Y;
 	AdjustWidth();
 
-	if (!ViewFile.Opened())
+	if (!vOpened())
 	{
 		if (!strFileName.IsEmpty() && ((nMode == SHOW_RELOAD) || (nMode == SHOW_HEX)))
 		{
@@ -1127,9 +1173,9 @@
 		case MCODE_C_SELECTED:
 			return (__int64)(SelectSize >= 0 ?TRUE:FALSE);
 		case MCODE_C_EOF:
-			return (__int64)(LastPage || !ViewFile.Opened());
+			return (__int64)(LastPage || !vOpened());
 		case MCODE_C_BOF:
-			return (__int64)(!FilePos || !ViewFile.Opened());
+			return (__int64)(!FilePos || !vOpened());
 		case MCODE_V_VIEWERSTATE:
 		{
 			DWORD MacroViewerState=0;
@@ -1223,7 +1269,7 @@
 		case KEY_CTRLINS:  case KEY_CTRLNUMPAD0:
 		case KEY_RCTRLINS: case KEY_RCTRLNUMPAD0:
 		{
-			if (SelectSize >= 0 && ViewFile.Opened())
+			if (SelectSize >= 0 && vOpened())
 			{
 				wchar_t *SelData = (wchar_t*)xf_malloc((size_t)SelectSize+1);
 				if ( SelData )
@@ -1254,7 +1300,7 @@
 		}
 		case KEY_IDLE:
 		{
-			if (ViewFile.Opened() && update_check_period >= 0)
+			if (vOpened() && update_check_period >= 0)
 			{
 				DWORD now_ticks = GetTickCount();
 				if ((int)(now_ticks - last_update_check) < update_check_period)
@@ -1262,7 +1308,11 @@
 				last_update_check = now_ticks;
 
 				FAR_FIND_DATA_EX NewViewFindData;
-				if (!apiGetFindDataEx(strFullFileName, NewViewFindData))
+				bool ok = vFile
+					? vFile->GetSize((PINT64)&NewViewFindData.nFileSize) && vFile->GetUpdateTime(&NewViewFindData.ftLastWriteTime)
+					: apiGetFindDataEx(strFullFileName, NewViewFindData) != 0
+				;
+				if ( !ok )
 					return TRUE;
 
 				ViewFile.GetSize(NewViewFindData.nFileSize); // Required! -- thanks Dzirt2005
@@ -1275,7 +1325,8 @@
 					SetFileSize();
 
 					Reader.Clear(); // ���� ���� �� ��� ����?
-					ViewFile.FlushBuffers();
+					if ( !vFile )
+						ViewFile.FlushBuffers();
 					vseek(0, SEEK_CUR); // reset vgetc state
 					lcache_ready = false; // reset start-lines cache
 
@@ -1435,7 +1486,7 @@
 				if (nCodePage == (CP_AUTODETECT & 0xffff))
 				{
 					__int64 fpos = vtell();
-					bool detect = GetFileFormat(ViewFile,nCodePage,&Signature,true) && IsCodePageSupported(nCodePage);
+					bool detect = vGetFileFormat(nCodePage, true) && IsCodePageSupported(nCodePage);
 					vseek(fpos, SEEK_SET);
 					if (!detect)
 						nCodePage = Opt.ViOpt.AnsiCodePageAsDefault ? GetACP() : GetOEMCP();
@@ -1452,7 +1503,7 @@
 		case KEY_ALTF8:
 		case KEY_RALTF8:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				LastPage = 0;
 				GoTo();
@@ -1514,7 +1565,7 @@
 		}
 		case KEY_UP: case KEY_NUMPAD8: case KEY_SHIFTNUMPAD8:
 		{
-			if (FilePos>0 && ViewFile.Opened())
+			if (FilePos>0 && vOpened())
 			{
 				Up(1);	// LastPage = 0
 
@@ -1535,7 +1586,7 @@
 		}
 		case KEY_DOWN: case KEY_NUMPAD2:  case KEY_SHIFTNUMPAD2:
 		{
-			if (!LastPage && ViewFile.Opened())
+			if (!LastPage && vOpened())
 			{
 				if (VM.Hex)
 				{
@@ -1550,7 +1601,7 @@
 		}
 		case KEY_PGUP: case KEY_NUMPAD9: case KEY_SHIFTNUMPAD9: case KEY_CTRLUP: case KEY_RCTRLUP:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				Up(Y2-Y1);
 				Show();
@@ -1560,7 +1611,7 @@
 		}
 		case KEY_PGDN: case KEY_NUMPAD3:  case KEY_SHIFTNUMPAD3: case KEY_CTRLDOWN: case KEY_RCTRLDOWN:
 		{
-			if (LastPage || !ViewFile.Opened())
+			if (LastPage || !vOpened())
 				return TRUE;
 
 			FilePos = EndOfScreen(-1); // start of last screen line
@@ -1588,7 +1639,7 @@
 		}
 		case KEY_LEFT: case KEY_NUMPAD4: case KEY_SHIFTNUMPAD4:
 		{
-			if (LeftPos>0 && ViewFile.Opened())
+			if (LeftPos>0 && vOpened())
 			{
 				if (VM.Hex && LeftPos>80-Width)
 					LeftPos=Max(80-Width,1);
@@ -1601,7 +1652,7 @@
 		}
 		case KEY_RIGHT: case KEY_NUMPAD6: case KEY_SHIFTNUMPAD6:
 		{
-			if (LeftPos<MAX_VIEWLINE && ViewFile.Opened() && !VM.Hex && !VM.Wrap)
+			if (LeftPos<MAX_VIEWLINE && vOpened() && !VM.Hex && !VM.Wrap)
 			{
 				LeftPos++;
 				Show();
@@ -1612,7 +1663,7 @@
 		case KEY_CTRLLEFT:  case KEY_CTRLNUMPAD4:
 		case KEY_RCTRLLEFT: case KEY_RCTRLNUMPAD4:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				if (VM.Hex)
 				{
@@ -1631,7 +1682,7 @@
 		case KEY_CTRLRIGHT:  case KEY_CTRLNUMPAD6:
 		case KEY_RCTRLRIGHT: case KEY_RCTRLNUMPAD6:
 		{
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				if (VM.Hex)
 				{
@@ -1654,7 +1705,7 @@
 		case KEY_RCTRLSHIFTLEFT:   case KEY_RCTRLSHIFTNUMPAD4:
 		{
 			// ������� �� ����� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				LeftPos = 0;
 				Show();
@@ -1666,7 +1717,7 @@
 		case KEY_RCTRLSHIFTRIGHT:    case KEY_RCTRLSHIFTNUMPAD6:
 		{
 			// ������� �� ���� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				int I, Y, Len, MaxLen = 0;
 
@@ -1693,12 +1744,12 @@
 		case KEY_HOME:        case KEY_NUMPAD7:   case KEY_SHIFTNUMPAD7:
 
 			// ������� �� ����� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 				LeftPos=0;
 
 		case KEY_CTRLPGUP:    case KEY_CTRLNUMPAD9:
 		case KEY_RCTRLPGUP:   case KEY_RCTRLNUMPAD9:
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				FilePos=0;
 				Show();
@@ -1710,13 +1761,13 @@
 		case KEY_END:         case KEY_NUMPAD1: case KEY_SHIFTNUMPAD1:
 
 			// ������� �� ���� �����
-			if (ViewFile.Opened())
+			if (vOpened())
 				LeftPos=0;
 
 		case KEY_CTRLPGDN:    case KEY_CTRLNUMPAD3:
 		case KEY_RCTRLPGDN:   case KEY_RCTRLNUMPAD3:
 
-			if (ViewFile.Opened())
+			if (vOpened())
 			{
 				/* $ 15.08.2002 IS
 				   �� ������ ������, ���� ������� ������ �� �������� �������
@@ -2006,7 +2057,7 @@
 {
 	assert( nlines > 0 );
 
-	if (!ViewFile.Opened())
+	if (!vOpened())
 		return;
 
 	LastPage = 0;
@@ -3021,7 +3072,7 @@
 */
 void Viewer::Search(int Next,int FirstChar)
 {
-	if (!ViewFile.Opened() || (Next && strLastSearchStr.IsEmpty()))
+	if (!vOpened() || (Next && strLastSearchStr.IsEmpty()))
 		return;
 
 	string strSearchStr, strMsgStr;
@@ -3566,12 +3617,16 @@
 	}
 
 	vgetc_ready = false;
-	return ViewFile.SetPointer(Offset, nullptr, Whence);
+
+	return vFile
+		? vFile->SetPointer(Offset, nullptr, Whence)
+		: ViewFile.SetPointer(Offset, nullptr, Whence)
+	;
 }
 
 __int64 Viewer::vtell()
 {
-	__int64 Ptr = ViewFile.GetPointer();
+	__int64 Ptr = vFile ? vFile->GetPointer() : ViewFile.GetPointer();
 
 	if (vgetc_ready)
 		Ptr -= (vgetc_cb - vgetc_ib);
@@ -3584,7 +3639,7 @@
 	if (vgetc_ready && vgetc_ib < vgetc_cb)
 		return false;
 	else
-		return ViewFile.Eof();
+		return vFile ? vFile->Eof() : ViewFile.Eof();
 }
 
 bool Viewer::vgetc(wchar_t *pCh)
@@ -3592,7 +3647,7 @@
 	if (!vgetc_ready)
 		vgetc_cb = vgetc_ib = (int)(vgetc_composite = 0);
 
-	if (vgetc_cb - vgetc_ib < 4 && !ViewFile.Eof())
+	if (vgetc_cb - vgetc_ib < 4 && !(vFile ? vFile->Eof() : ViewFile.Eof()))
 	{
 		vgetc_cb -= vgetc_ib;
 		if (vgetc_cb && vgetc_ib)
@@ -3878,12 +3933,18 @@
 
 void Viewer::SetFileSize()
 {
-	if (!ViewFile.Opened())
+	if (!vOpened())
 		return;
 
-	UINT64 uFileSize=0; // BUGBUG, sign
-	ViewFile.GetSize(uFileSize);
-	FileSize=uFileSize;
+	union { UINT64 u64FileSize; INT64 i64FileSize; } u;
+	u.i64FileSize = 0;
+
+	if ( vFile )
+		vFile->GetSize(&u.i64FileSize);
+	else
+		ViewFile.GetSize(u.u64FileSize);
+
+	FileSize = u.i64FileSize;
 }
 
 
@@ -3899,7 +3960,7 @@
 //
 void Viewer::SelectText(const __int64 &match_pos,const __int64 &search_len, const DWORD flags)
 {
-	if (!ViewFile.Opened())
+	if (!vOpened())
 		return;
 
 	SelectPos = match_pos;
Index: plugin.hpp
===================================================================
--- plugin.hpp	(revision 6635)
+++ plugin.hpp	(working copy)
@@ -852,7 +852,6 @@
 
 typedef void (WINAPI *FARAPIRESTORESCREEN)(HANDLE hScreen);
 
-
 typedef int (WINAPI *FARAPIGETDIRLIST)(
     const wchar_t *Dir,
     struct PluginPanelItem **pPanelItem,
@@ -878,7 +877,8 @@
 	VF_ENABLE_F6             = 0x0000000000000004ULL,
 	VF_DISABLEHISTORY        = 0x0000000000000008ULL,
 	VF_IMMEDIATERETURN       = 0x0000000000000100ULL,
-	VF_DELETEONLYFILEONCLOSE = 0x0000000000000200ULL;
+	VF_DELETEONLYFILEONCLOSE = 0x0000000000000200ULL,
+	VF_DIRECT_VFILE          = 0x0000000000000400ULL;
 
 typedef int (WINAPI *FARAPIVIEWER)(
     const wchar_t *FileName,
@@ -891,6 +891,49 @@
     UINT CodePage
 );
 
+enum VFILE_VERSION
+{ VFile_Version_Base    = 0x100 // 1.00
+, VFile_Version_Current = 0x100
+};
+
+typedef int   (WINAPI *VERSION_SVFILE)(void *ctx);
+typedef const wchar_t* (WINAPI *GETNAME_SVFILE)(void *ctx, BOOL full);
+typedef BOOL  (WINAPI *SETPOINTER_SVFILE)(void *ctx, INT64 off, PINT64 ppos, int whence);
+typedef INT64 (WINAPI *GETPOINTER_SVFILE)(void *ctx);
+typedef BOOL  (WINAPI *EOF_SVFILE)(void *ctx);
+typedef BOOL  (WINAPI *GETSIZE_SVFILE)(void *ctx, INT64 *fsize);
+typedef BOOL  (WINAPI *GETUPDATETIME_SVFILE)(void *ctx, FILETIME *ftime);
+typedef int   (WINAPI *UPDATECHECKPERIOD_SVFILE)(void *ctx);
+typedef BOOL  (WINAPI *READ_SVFILE)(void *ctx, void *buff, DWORD cb, DWORD* nr);
+typedef BOOL  (WINAPI *WRITE_SVFILE)(void *ctx, const void *buff, DWORD nb, DWORD* nw);
+
+struct SVFile
+{
+	void *ctx;
+
+	VERSION_SVFILE Version;
+	GETNAME_SVFILE GetName;
+	SETPOINTER_SVFILE SetPointer;	
+	GETPOINTER_SVFILE GetPointer;
+	EOF_SVFILE Eof;
+	GETSIZE_SVFILE GetSize;
+	GETUPDATETIME_SVFILE GetUpdateTime;
+	UPDATECHECKPERIOD_SVFILE UpdateCheckPeriod;
+	READ_SVFILE Read;
+	WRITE_SVFILE Write;
+};
+
+typedef int (WINAPI *FARAPIVIEWER_VFILE)(
+	struct SVFile *svFile,
+	const wchar_t *Title,
+	int X1,
+	int Y1,
+	int X2,
+	int Y2,
+	VIEWER_FLAGS Flags,
+	UINT CodePage
+);
+
 typedef unsigned __int64 EDITOR_FLAGS;
 static const EDITOR_FLAGS
 	EF_NONMODAL              = 0x0000000000000001ULL,
@@ -2197,6 +2240,8 @@
 	FARAPIREGEXPCONTROL    RegExpControl;
 	FARAPIMACROCONTROL     MacroControl;
 	FARAPISETTINGSCONTROL  SettingsControl;
+
+	FARAPIVIEWER_VFILE     ViewerVF;
 };
 
 
Index: plugapi.hpp
===================================================================
--- plugapi.hpp	(revision 6635)
+++ plugapi.hpp	(working copy)
@@ -89,11 +89,15 @@
 int WINAPI FarGetDirList(const wchar_t *Dir, PluginPanelItem **pPanelItem, size_t *pItemsNumber);
 void WINAPI FarFreeDirList(PluginPanelItem *PanelItem, size_t nItemsNumber);
 
-int WINAPI FarViewer(const wchar_t *FileName,const wchar_t *Title,
+int WINAPI FarViewer(const wchar_t *FileName, const wchar_t *Title,
                      int X1,int Y1,int X2,int Y2,unsigned __int64 Flags, UINT CodePage);
+int WINAPI FarViewerVFile(struct SVFile *svFile, const wchar_t *Title,
+	int X1,int Y1,int X2,int Y2,unsigned __int64 Flags, UINT CodePage);
+
 int WINAPI FarEditor(const wchar_t *FileName,const wchar_t *Title,
                      int X1,int Y1,int X2, int Y2,unsigned __int64 Flags,
                      int StartLine,int StartChar, UINT CodePage);
+
 void WINAPI FarText(int X,int Y,const FarColor* Color,const wchar_t *Str);
 
 INT_PTR WINAPI FarEditorControl(int EditorID, EDITOR_CONTROL_COMMANDS Command, int Param1, void* Param2);
Index: far.vcxproj.filters
===================================================================
--- far.vcxproj.filters	(revision 6635)
+++ far.vcxproj.filters	(working copy)
@@ -545,6 +545,9 @@
     <ClCompile Include="nsUniversalDetectorEx.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="vFile.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="elevation.hpp">
@@ -1081,6 +1084,9 @@
     <ClInclude Include="panelctype.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="vFile.hpp">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="bootstrap\lang.inc">
Virtual-Viewer-plain_C.diff (37,297 bytes)   

2useven10

2011-08-27 08:22

developer   bugnote:0007556

ну например так...

vskirdin

2011-08-29 13:54

administrator   bugnote:0007567

Что ЭТО дает FAR`у?
Что ЭТО дает плагинам? (юзерам, пользующим такие плагины).
Допустим я туп и мне нужно обычными словами рассказать в чем профит?
(а по сути - дать толковое описание для Писания, чтобы плагинописатели доставали не глупыми вопросами, а по существу)

2useven10

2011-08-30 12:27

developer   bugnote:0007574

Last edited: 2011-08-30 13:47

http://forum.farmanager.com/viewtopic.php?f=6&t=6339&p=84720#p84720
То что написано в Description частично устарело

vskirdin

2011-09-02 07:52

administrator   bugnote:0007601

пробуем: http://skirda-file.googlecode.com/files/Mantis0001836.7z
неплохо бы простенький плагин...

vskirdin

2013-07-05 11:10

administrator   bugnote:0011245

Чё у нас с этим Инцом?

2useven10

2013-07-05 13:03

developer   bugnote:0011246

похоронен.

vskirdin

2013-07-05 13:10

administrator   bugnote:0011247

Закрываем?

2useven10

2013-07-05 13:33

developer   bugnote:0011248

Да, даже если продолжать, всё равно проще заново...

Issue History

Date Modified Username Field Change
2011-07-20 12:02 2useven10 New Issue
2011-07-20 12:02 2useven10 File Added: Virtual_Viewer.diff
2011-07-21 13:13 2useven10 File Added: Virtual_Viewer1.diff
2011-07-21 13:19 2useven10 Note Added: 0007289
2011-07-22 12:56 2useven10 File Added: Virtual_Viewer2.diff
2011-07-22 13:01 2useven10 Note Added: 0007293
2011-07-22 13:45 samlyukov Note Added: 0007295
2011-07-24 09:01 zg Note Added: 0007305
2011-07-24 12:40 2useven10 Note Added: 0007306
2011-07-24 13:58 zg Note Added: 0007307
2011-07-24 16:38 vskirdin Note Added: 0007308
2011-08-27 08:22 2useven10 File Added: Virtual-Viewer-plain_C.diff
2011-08-27 08:22 2useven10 Note Added: 0007556
2011-08-29 13:54 vskirdin Note Added: 0007567
2011-08-30 12:27 2useven10 Note Added: 0007574
2011-08-30 12:28 2useven10 Note Edited: 0007574
2011-08-30 13:47 2useven10 Note Edited: 0007574
2011-09-02 07:52 vskirdin Note Added: 0007601
2011-12-23 08:32 alexy Project Far Manager => Wishes
2013-07-05 11:10 vskirdin Note Added: 0011245
2013-07-05 13:03 2useven10 Note Added: 0011246
2013-07-05 13:10 vskirdin Note Added: 0011247
2013-07-05 13:33 2useven10 Note Added: 0011248
2013-07-05 14:21 2useven10 Build => 0
2013-07-05 14:21 2useven10 Status new => closed
2013-07-05 14:21 2useven10 Assigned To => 2useven10
2013-07-05 14:21 2useven10 Resolution open => suspended