#include "fsplugin.h"
#include "cunicode.h"
#include <shlwapi.h> // wnsprinf()
#include "Xml.h"
#define pluginrootlen 1
#define vsnprintf _vsnprintf
HINSTANCE hInstance;
char inifilename[MAX_PATH]; // Unused in this plugin, may be used to save data
volatile bool wantStop;
static void _cdecl debug(char*t,...) {
#ifdef _DEBUG
char buf[1024];
va_list va;
va_start(va,t);
vsnprintf(buf,elemof(buf),t,va);
OutputDebugStringA(buf);
va_end(va);
#endif
}
extern "C" BOOL APIENTRY _DllMainCRTStartup(HINSTANCE h,DWORD reason,void*) {
debug("DllMain(%p,%d)\n",h,reason);
switch (reason) {
case DLL_PROCESS_ATTACH: {
hInstance=h;
DisableThreadLibraryCalls(h);
}break;
}
return TRUE;
}
int PluginNumber;
tProgressProc ProgressProc;
tLogProc LogProc;
tRequestProc RequestProc;
tProgressProcW ProgressProcW;
tLogProcW LogProcW;
tRequestProcW RequestProcW;
int WINAPI FsInit(int n,tProgressProc p1,tLogProc p2,tRequestProc p3) {
PluginNumber=n;
ProgressProc=p1;
LogProc=p2;
RequestProc=p3;
return 0;
}
int WINAPI FsInitW(int n,tProgressProcW p1,tLogProcW p2,tRequestProcW p3) {
debug("%s(%d,%p,%p,%p)\n","FsInitW",n,p1,p2,p3);
PluginNumber=n;
ProgressProcW=p1;
LogProcW=p2;
RequestProcW=p3;
return 0;
}
struct FindHandle{
int iItem;
const Xml::Node*item;
operator HANDLE() {return HANDLE(this);}
FindHandle(const Xml::Node*n):item(n),iItem(0) {}
};
struct LoadedFile{
Xml*xml; // !=0 when loaded
int dirty; // counts number of changes
DWORD packer_id;
FILETIME getLastMod() const;
char displayname[64]; // TODO: Katalogname aus XML-Datei
char filename[MAX_PATH];
bool load();
bool save();
~LoadedFile();
static bool convertFile(HANDLE,HANDLE,const char*);
static bool unpackFile(HANDLE&,const char*);
static bool packFile(HANDLE&,const char*);
private:
HANDLE open(DWORD creation=OPEN_EXISTING) const;
};
LoadedFile::~LoadedFile() {
if (xml) {
if (dirty) save();
delete xml;
}
}
HANDLE LoadedFile::open(DWORD creation) const{
int l=MultiByteToWideChar(CP_UTF8,0,filename,-1,0,0);
WCHAR*n=(WCHAR*)_alloca(l*sizeof*n);
MultiByteToWideChar(CP_UTF8,0,filename,-1,n,l);
SECURITY_ATTRIBUTES sa={sizeof sa,0,TRUE};
return CreateFileW(n,
creation==OPEN_EXISTING?GENERIC_READ:GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ,&sa,creation,0,0);
}
FILETIME LoadedFile::getLastMod() const{
union{
ULONGLONG ull;
FILETIME ft;
}ret={-1};
HANDLE h=open();
if (h!=INVALID_HANDLE_VALUE) {
GetFileTime(h,0,0,&ret.ft);
CloseHandle(h);
}
return ret.ft;
}
bool LoadedFile::convertFile(HANDLE hr,HANDLE hw,const char*cmd) {
int l=MultiByteToWideChar(CP_UTF8,0,cmd,-1,0,0);
WCHAR*p=(WCHAR*)_alloca(l*sizeof*p);
MultiByteToWideChar(CP_UTF8,0,cmd,-1,p,l);
STARTUPINFOW si;
memset(&si,0,sizeof si);
si.cb=sizeof si;
si.dwFlags=STARTF_USESTDHANDLES|STARTF_FORCEOFFFEEDBACK;
// SetHandleInformation(hr,HANDLE_FLAG_INHERIT,HANDLE_FLAG_INHERIT);
// SetHandleInformation(hw,HANDLE_FLAG_INHERIT,HANDLE_FLAG_INHERIT);
si.hStdInput=hr;
si.hStdOutput=hw;
si.hStdError=hw;
PROCESS_INFORMATION pi;
if (!CreateProcessW(0,p,0,0,TRUE,CREATE_NO_WINDOW,0,0,&si,&pi)) return false;
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(hr); // CreateProcess ruft intern DuplicateHandle()
CloseHandle(hw);
return true;
}
// Packt Datei im Worker-Thread aus und tauscht das Dateihandle gegen das Read-Pipe-Handle
bool LoadedFile::unpackFile(HANDLE&h,const char*cmd) {
HANDLE hr, hw;
SECURITY_ATTRIBUTES sa={sizeof sa,0,TRUE};
if (!CreatePipe(&hr,&hw,&sa,Xml::BUFSIZE)) return false;
if (!convertFile(h,hw,cmd)) return false;
h=hr;
return true;
}
// Packt Datei im Worker-Thread ein und tauscht das Dateihandle gegen das Write-Pipe-Handle
bool LoadedFile::packFile(HANDLE&h,const char*cmd) {
HANDLE hr, hw;
SECURITY_ATTRIBUTES sa={sizeof sa,0,TRUE};
if (!CreatePipe(&hr,&hw,&sa,Xml::BUFSIZE)) return false;
if (!convertFile(hr,h,cmd)) return false;
h=hw;
return true;
}
bool LoadedFile::load() {
if (xml) return true; // bereits geladen
HANDLE h=open();
if (h==INVALID_HANDLE_VALUE) return false;
debug("load %s start\n",filename);
DWORD br;
ReadFile(h,&packer_id,4,&br,0);
SetFilePointer(h,0,0,FILE_BEGIN);
// Kann eine Weile dauern! ProgressProcW() aufrufen
WCHAR f[256],s[64];
MultiByteToWideChar(CP_UTF8,0,filename,-1,f,elemof(f));
LoadStringW(hInstance,3,s,elemof(s)); // "RAM-Speicher"
ProgressProcW(PluginNumber,f,s,0);
bool ret=true;
// unpackFile() geht schnell (blockiert kaum),
// denn das ersetzt <h> durch eine Pipe mit einem Fütter-Thread
switch (packer_id) {
case 0x00088B1F: ret=unpackFile(h,"gunzip"); break;
case 0x31685A42: ret=unpackFile(h,"bunzip2"); break;
}
if (ret) {
xml=new Xml(h);
ret=xml->parse(); // DAS dauert lange! Lässt sich nur schwerlich parallelisieren.
}
ProgressProcW(PluginNumber,f,s,100);
debug("load %s %s\n",filename,ret?"success":"fail");
if (!ret) debug("Error %x at %s:%u:%u\n",filename,xml->ec,xml->line+1,xml->pos+1);
return ret;
}
bool LoadedFile::save() {
// make backup!!
HANDLE h=open(CREATE_ALWAYS);
if (h==INVALID_HANDLE_VALUE) return false;
switch (packer_id) {
case 0x00088B1F: if (!packFile(h,"gzip")) return false; break;
case 0x31685A42: if (!packFile(h,"bzip2")) return false; break;
}
xml->hStream=h;
return xml->serialize();
}
// std::vector beißt sich mit /NOD (nodefaultlib)
class LoadedFiles{
int fill;
LoadedFile a[10];
public:
const LoadedFile&operator[](int i) const {return a[i];}
LoadedFile&operator[](int i) {return a[i];}
int size() const {return fill;}
void size(int s) {fill=s;}
}loadedFiles;
static bool hasAttrName(const Xml::Node*n,void*p) {
const Xml::Node*a=n->findChildNode(Xml::Node::Attr,"name");
if (!a) return false;
return !strcmp(a->value,(const char*)p);
}
static const Xml::Node*StringToNode(const WCHAR*s) {
if (s[0]!='\\') return 0; // Nur absoluter Pfad erlaubt!
if (!s[1]) return 0; // Wurzel = Liste der Dateinamen
int len=WideCharToMultiByte(CP_UTF8,0,s+1,-1,0,0,0,0);
char*p=(char*)_alloca(len+2);
WideCharToMultiByte(CP_UTF8,0,s+1,-1,p,len,0,0);
p[len]=0; p[len+1]=0;
for (char*q=p;;++q) {
q=strchr(q,'\\');
if (q) *q=0; else break; // Doppelnulltertimierten Pfadstring generieren
}
for (int i=0; i<loadedFiles.size(); i++) {
if (!lstrcmp(loadedFiles[i].displayname,p)) { // Dateiname gefunden
if (!loadedFiles[i].load()) return 0; // Kann nicht laden
const Xml::Node*n=loadedFiles[i].xml->root->findChildNode(Xml::Node::Element,"catalog");
for (char*q=p; *(q+=lstrlen(q)+1);) {
n=n->findChildNode(Xml::Node::Element,hasAttrName,(void*)q);
if (!n) return 0;
}
return n;
}
}
return 0;
}
enum{
eRoot=32, // erlaubt das Auflisten von Katalogen (falls mehrere; unzulässiges XML)
eCatalog=16,
eMedia=8,
eDir=4,
eFile=2,
eOther=1,
};
BYTE classify(const Xml::Node*n,BYTE check=0xFF) { // Liefert 1-aus-n-Bitmaske
if (!n) return 0; // nichts
if (check&eRoot && n->type==Xml::Node::root) return eRoot;
if (n->type!=Xml::Node::Element) return 0; // nichts
if (check&eCatalog && !lstrcmp(n->name,"catalog")) return eCatalog;
if (check&eMedia && !lstrcmp(n->name,"media")) return eMedia;
if (check&eDir && !lstrcmp(n->name,"directory"))return eDir;
if (check&eFile && !lstrcmp(n->name,"file")) return eFile;
return check&eOther;
}
bool setFindData(const Xml::Node*c,WIN32_FIND_DATAW&W) {
if (!c) return false;
W.dwFileAttributes=classify(c,eFile)?0:FILE_ATTRIBUTE_DIRECTORY;
W.ftLastWriteTime.dwHighDateTime=DWORD(-1);
W.ftLastWriteTime.dwLowDateTime=DWORD(-2);
W.nFileSizeHigh=0;
W.nFileSizeLow=0;
const Xml::Node*a=c->findChildNode(Xml::Node::Attr,"time");
if (a) {
SYSTEMTIME st;
st.wDayOfWeek=st.wMilliseconds=0;
if (sscanf(a->value,"%hu-%hu-%hu %hu:%hu:%hu",
&st.wYear,&st.wMonth,&st.wDay,
&st.wHour,&st.wMinute,&st.wSecond)==6) {
FILETIME ft;
SystemTimeToFileTime(&st,&ft);
LocalFileTimeToFileTime(&ft,&W.ftLastWriteTime);
}
}
if (!W.dwFileAttributes) { // Datei, kein Verzeichnis
a=c->findChildNode(Xml::Node::Attr,"size");
if (a) {
int l=lstrlen(a->value);
char*s=(char*)_alloca(l+1);
memcpy(s,a->value,l+1);
char*k=(char*)memchr(s,',',l);
if (k) *k='.';
float fsz;
char kmg[2];
if (sscanf(s,"%f %1[KMGT]b",
&fsz,kmg)==2) {
switch (kmg[0]) {
case 'T': fsz*=1000;
case 'G': fsz*=1000;
case 'M': fsz*=1000; // Auch wenn das wahrscheinlich nicht stimmt, sieht im Commander besser aus
}
ULONGLONG sz=ULONGLONG(fsz*1000);
W.nFileSizeHigh=DWORD(sz>>32);
W.nFileSizeLow=DWORD(sz);
}
}
}
a=c->findChildNode(Xml::Node::Attr,"name");
if (a) {
unicopy(CP_UTF8,W.cFileName,elemof(W.cFileName),a->value);
}else *W.cFileName=0; // ohne Name (Datenbank-Bug)
*W.cAlternateFileName=0;
return true;
}
static void initfinddata(WIN32_FIND_DATAW&W) {
memset(&W,0,sizeof W);
W.ftLastWriteTime.dwHighDateTime=DWORD(-1);
W.ftLastWriteTime.dwLowDateTime=DWORD(-2);
}
static bool classify1(const Xml::Node*n,void*) {
return !!classify(n,/*eCatalog|*/eMedia|eDir|eFile);
}
HANDLE WINAPI FsFindFirstW(WCHAR*Path,WIN32_FIND_DATAW&W) {
// debug("%s(%S,%p)\n","FsFindFirstW",Path,&W);
initfinddata(W);
if (Path[0]=='\\' && !Path[1]) {
W.dwFileAttributes=FILE_ATTRIBUTE_READONLY; // Kein Verzeichnis zum Öffnen
FindHandle*lf=new FindHandle(0);
LoadStringW(hInstance,2,W.cFileName,elemof(W.cFileName)); //"Neuer Katalog"
return lf;
}
const Xml::Node*n=StringToNode(Path);
if (!classify(n,/*eRoot|*/eCatalog|eMedia|eDir)) return INVALID_HANDLE_VALUE;
const Xml::Node*c=n->findChildNode(Xml::Node::Element,classify1,0);
if (!setFindData(c,W)) {
SetLastError(ERROR_NO_MORE_FILES);
return INVALID_HANDLE_VALUE;
}
return new FindHandle(c);
}
HANDLE WINAPI FsFindFirst(char* Path,WIN32_FIND_DATA&A) {
WIN32_FIND_DATAW W;
WCHAR PathW[LONGPATH_MAX];
HANDLE retval=FsFindFirstW(unicopy(PathW,elemof(PathW),Path),W);
if (retval!=INVALID_HANDLE_VALUE) unicopy(A,W);
return retval;
}
BOOL WINAPI FsFindNextW(HANDLE Hdl,WIN32_FIND_DATAW&W) {
// debug("%s(%p,%p)\n","FsFindNextW",Hdl,&W);
initfinddata(W);
FindHandle*fh=(FindHandle*)Hdl;
if (!fh->item) { // generate loaded files list
if (++fh->iItem>loadedFiles.size()) {
SetLastError(ERROR_NO_MORE_FILES);
return false;
}
W.dwFileAttributes=FILE_ATTRIBUTE_DIRECTORY;
LoadedFile&lf=loadedFiles[fh->iItem-1];
W.ftLastWriteTime=lf.getLastMod();
unicopy(CP_UTF8,W.cFileName,elemof(W.cFileName),lf.displayname);
return true;
}
++fh->iItem;
fh->item=fh->item->next->findElement(); // Textnodes dazwischen ausklammern
if (!setFindData(fh->item,W)) {
SetLastError(ERROR_NO_MORE_FILES);
return false;
}
return true;
}
BOOL WINAPI FsFindNext(HANDLE Hdl,WIN32_FIND_DATA&A) {
WIN32_FIND_DATAW W;
unicopy(W,A);
BOOL retval=FsFindNextW(Hdl,W);
if (retval) unicopy(A,W);
return retval;
}
int WINAPI FsFindClose(HANDLE Hdl) {
// debug("%s(%p)\n","FsFindClose",Hdl);
FindHandle*fh=(FindHandle*)Hdl;
delete fh;
return 0;
}
void WINAPI FsGetDefRootName(char*DefRootName,int maxlen) {
debug("%s(%p,%d)\n","FsGetDefRootName",DefRootName,maxlen);
LoadString(hInstance,1,DefRootName,maxlen); // "CD-Katalog"
}
#if 0
BOOL WINAPI FsMkDir(const char*Path) {
WCHAR wbuf[LONGPATH_MAX];
return FsMkDirW(unicopy(wbuf,elemof(wbuf),Path));
}
BOOL WINAPI FsMkDirW(const WCHAR*Path) {
if (lstrlenW(Path)<pluginrootlen+2) return false;
return CreateDirectoryT(Path+pluginrootlen,NULL);
}
int WINAPI FsExecuteFile(HWND MainWin,const char*RemoteName,const char*Verb) {
if (lstrlen(RemoteName)<pluginrootlen+2) return FS_EXEC_ERROR;
if (!lstrcmpi(Verb,"open")) return FS_EXEC_YOURSELF;
if (!lstrcmpi(Verb,"properties")) {
SHELLEXECUTEINFO shex;
memset(&shex,0,sizeof(shex));
shex.fMask=SEE_MASK_INVOKEIDLIST;
shex.cbSize=sizeof(shex);
shex.nShow=SW_SHOW;
shex.hwnd=MainWin;
shex.lpVerb=Verb;
shex.lpFile=RemoteName+pluginrootlen;
if (!ShellExecuteEx(&shex)) return FS_EXEC_ERROR;
return FS_EXEC_OK;
}
return FS_EXEC_ERROR;
}
int WINAPI FsExecuteFileW(HWND MainWin,const WCHAR*RemoteName,const WCHAR*Verb) {
SHELLEXECUTEINFOW shex;
if (lstrlenW(RemoteName)<pluginrootlen+2)
return FS_EXEC_ERROR;
if (lstrcmpiW(Verb,L"open")==0) {
return FS_EXEC_YOURSELF;
} else if (lstrcmpiW(Verb,L"properties")==0) {
memset(&shex,0,sizeof(shex));
shex.fMask=SEE_MASK_INVOKEIDLIST;
shex.cbSize=sizeof(shex);
shex.nShow=SW_SHOW;
shex.hwnd=MainWin;
shex.lpVerb=Verb;
shex.lpFile=RemoteName+pluginrootlen;
if (!ShellExecuteExW(&shex))
return FS_EXEC_ERROR;
else
return FS_EXEC_OK;
} else
return FS_EXEC_ERROR;
}
int WINAPI FsRenMovFile(const char*OldName,const char*NewName,BOOL Move,BOOL OverWrite,RemoteInfoStruct* ri) {
WCHAR OldNameW[LONGPATH_MAX],NewNameW[LONGPATH_MAX];
return FsRenMovFileW(
unicopy(OldNameW,elemof(OldNameW),OldName),
unicopy(NewNameW,elemof(NewNameW),NewName),
Move,OverWrite,ri);
}
int WINAPI FsRenMovFileW(const WCHAR* OldName,const WCHAR* NewName,BOOL Move,BOOL OverWrite,RemoteInfoStruct* ri) {
if (lstrlenW(OldName)<pluginrootlen+2 || lstrlenW(NewName)<pluginrootlen+2)
return FS_FILE_NOTFOUND;
int err=ProgressProcT(OldName,NewName,0);
if (err)
return FS_FILE_USERABORT;
if (Move) {
if (OverWrite)
DeleteFileT(NewName+pluginrootlen);
if (MoveFileT(OldName+pluginrootlen,NewName+pluginrootlen))
return FS_FILE_OK;
} else {
if (CopyFileT(OldName+pluginrootlen,NewName+pluginrootlen,!OverWrite))
return FS_FILE_OK;
}
switch(GetLastError()) {
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
case ERROR_ACCESS_DENIED:
return FS_FILE_NOTFOUND;
case ERROR_FILE_EXISTS:
return FS_FILE_EXISTS;
default:
return FS_FILE_WRITEERROR;
}
err=ProgressProcT(OldName,NewName,100);
if (err)
return FS_FILE_USERABORT;
}
int WINAPI FsGetFileW(WCHAR* RemoteName,WCHAR* LocalName,int CopyFlags,RemoteInfoStruct* ri)
{
int err;
BOOL ok,OverWrite,Resume,Move;
OverWrite=CopyFlags & FS_COPYFLAGS_OVERWRITE;
Resume=CopyFlags & FS_COPYFLAGS_RESUME;
Move=CopyFlags & FS_COPYFLAGS_MOVE;
if (Resume)
return FS_FILE_NOTSUPPORTED;
if (lstrlenW(RemoteName)<pluginrootlen+2)
return FS_FILE_NOTFOUND;
err=ProgressProcT(RemoteName,LocalName,0);
if (err)
return FS_FILE_USERABORT;
if (Move) {
if (OverWrite)
DeleteFileT(LocalName);
ok=MoveFileT(RemoteName+pluginrootlen,LocalName);
} else
ok=CopyFileT(RemoteName+pluginrootlen,LocalName,!OverWrite);
if (ok) {
ProgressProcT(RemoteName,LocalName,100);
return FS_FILE_OK;
} else {
err=GetLastError();
switch (err) {
case 2:
case 3:
case 4:
case 5:
return FS_FILE_NOTFOUND;
case ERROR_FILE_EXISTS:
return FS_FILE_EXISTS;
default:
return FS_FILE_READERROR;
}
}
}
int WINAPI FsGetFile(const char*RemoteName,const char*LocalName,int CopyFlags,RemoteInfoStruct* ri) {
WCHAR RemoteNameW[LONGPATH_MAX],LocalNameW[LONGPATH_MAX];
return FsGetFileW(
unicopy(RemoteNameW,elemof(RemoteNameW),RemoteName),
unicopy(LocalNameW,elemof(LocalNameW),LocalName),
CopyFlags,ri);
}
int WINAPI FsPutFileW(const WCHAR*LocalName,const WCHAR*RemoteName,int CopyFlags) {
int err;
BOOL ok,OverWrite,Resume,Move;
OverWrite=CopyFlags & FS_COPYFLAGS_OVERWRITE;
Resume=CopyFlags & FS_COPYFLAGS_RESUME;
Move=CopyFlags & FS_COPYFLAGS_MOVE;
if (Resume) return FS_FILE_NOTSUPPORTED;
if (lstrlenW(RemoteName)<pluginrootlen+2) return FS_FILE_NOTFOUND;
err=ProgressProcT(LocalName,RemoteName,0);
if (err) return FS_FILE_USERABORT;
if (Move) {
if (OverWrite) DeleteFileT(RemoteName+pluginrootlen);
ok=MoveFileT(LocalName,RemoteName+pluginrootlen);
}else ok=CopyFileT(LocalName,RemoteName+pluginrootlen,!OverWrite);
if (ok) {
ProgressProcT(RemoteName,LocalName,100);
return FS_FILE_OK;
}else{
err=GetLastError();
switch (err) {
case 2:
case 3:
case 4:
case 5: return FS_FILE_NOTFOUND;
case ERROR_FILE_EXISTS: return FS_FILE_EXISTS;
default: return FS_FILE_READERROR;
}
}
}
int WINAPI FsPutFile(const char*LocalName,const char*RemoteName,int CopyFlags) {
WCHAR LocalNameW[LONGPATH_MAX],RemoteNameW[LONGPATH_MAX];
return FsPutFileW(
unicopy(LocalNameW,elemof(LocalNameW),LocalName),
unicopy(RemoteNameW,elemof(RemoteNameW),RemoteName),
CopyFlags);
}
BOOL WINAPI FsDeleteFileW(const WCHAR*RemoteName) {
if (lstrlenW(RemoteName)<pluginrootlen+2) return false;
return DeleteFileT(RemoteName+pluginrootlen);
}
BOOL WINAPI FsDeleteFile(const char*RemoteName) {
WCHAR RemoteNameW[LONGPATH_MAX];
return FsDeleteFileW(unicopy(RemoteNameW,elemof(RemoteNameW),RemoteName));
}
BOOL WINAPI FsRemoveDirW(const WCHAR* RemoteName) {
if (lstrlenW(RemoteName)<pluginrootlen+2) return false;
return RemoveDirectoryT(RemoteName+pluginrootlen);
}
BOOL WINAPI FsRemoveDir(const char* RemoteName) {
WCHAR RemoteNameW[LONGPATH_MAX];
return FsRemoveDirW(unicopy(RemoteNameW,elemof(RemoteNameW),RemoteName));
}
BOOL WINAPI FsSetAttrW(const WCHAR* RemoteName,int NewAttr)
{
if (lstrlenW(RemoteName)<pluginrootlen+2)
return false;
if (NewAttr==0)
NewAttr=FILE_ATTRIBUTE_NORMAL;
return SetFileAttributesT(RemoteName+pluginrootlen,NewAttr);
}
BOOL WINAPI FsSetAttr(char* RemoteName,int NewAttr)
{
WCHAR RemoteNameW[LONGPATH_MAX];
return FsSetAttrW(unicopy(RemoteNameW,elemof(RemoteNameW),RemoteName),NewAttr);
}
BOOL WINAPI FsSetTimeW(WCHAR* RemoteName,FILETIME *CreationTime,
FILETIME *LastAccessTime,FILETIME *LastWriteTime)
{
if (lstrlenW(RemoteName)<pluginrootlen+2)
return false;
HANDLE filehandle = CreateFileT(RemoteName+pluginrootlen,
GENERIC_WRITE, // Open for writing
0, // Do not share
NULL, // No security
OPEN_EXISTING, // Existing file only
FILE_ATTRIBUTE_NORMAL, // Normal file
NULL);
if (filehandle==INVALID_HANDLE_VALUE)
return FALSE;
BOOL retval=SetFileTime(filehandle,CreationTime,LastAccessTime,LastWriteTime);
CloseHandle(filehandle);
return retval;
}
BOOL WINAPI FsSetTime(char* RemoteName,FILETIME *CreationTime,
FILETIME *LastAccessTime,FILETIME *LastWriteTime)
{
WCHAR RemoteNameW[LONGPATH_MAX];
return FsSetTimeW(unicopy(RemoteNameW,elemof(RemoteNameW),RemoteName),CreationTime,
LastAccessTime,LastWriteTime);
}
void WINAPI FsStatusInfo(char* RemoteDir,int InfoStartEnd,int InfoOperation)
{
// This function may be used to initialize variables and to flush buffers
/* char text[LONGPATH_MAX];
if (InfoStartEnd==FS_STATUS_START)
strcpy(text,"Start: ");
else
strcpy(text,"End: ");
switch (InfoOperation) {
case FS_STATUS_OP_LIST:
strcat(text,"Get directory list");
break;
case FS_STATUS_OP_GET_SINGLE:
strcat(text,"Get single file");
break;
case FS_STATUS_OP_GET_MULTI:
strcat(text,"Get multiple files");
break;
case FS_STATUS_OP_PUT_SINGLE:
strcat(text,"Put single file");
break;
case FS_STATUS_OP_PUT_MULTI:
strcat(text,"Put multiple files");
break;
case FS_STATUS_OP_RENMOV_SINGLE:
strcat(text,"Rename/Move/Remote copy single file");
break;
case FS_STATUS_OP_RENMOV_MULTI:
strcat(text,"Rename/Move/Remote copy multiple files");
break;
case FS_STATUS_OP_DELETE:
strcat(text,"Delete multiple files");
break;
case FS_STATUS_OP_ATTRIB:
strcat(text,"Change attributes of multiple files");
break;
case FS_STATUS_OP_MKDIR:
strcat(text,"Create directory");
break;
case FS_STATUS_OP_EXEC:
strcat(text,"Execute file or command line");
break;
case FS_STATUS_OP_CALCSIZE:
strcat(text,"Calculate space occupied by a directory");
break;
case FS_STATUS_OP_SEARCH:
strcat(text,"Search for file names");
break;
case FS_STATUS_OP_SEARCH_TEXT:
strcat(text,"Search for text in files");
break;
case FS_STATUS_OP_SYNC_SEARCH:
strcat(text,"Search files for sync comparison");
break;
case FS_STATUS_OP_SYNC_GET:
strcat(text,"download files during sync");
break;
case FS_STATUS_OP_SYNC_PUT:
strcat(text,"Upload files during sync");
break;
case FS_STATUS_OP_SYNC_DELETE:
strcat(text,"Delete files during sync");
break;
default:
strcat(text,"Unknown operation");
}
if (InfoOperation != FS_STATUS_OP_LIST) // avoid recursion due to re-reading!
MessageBox(0,text,RemoteDir,0);
*/
}
#endif
int WINAPI FsExtractCustomIconW(WCHAR* Path,int flags,HICON&ico) {
const Xml::Node*n=StringToNode(Path);
BYTE c=classify(n,eRoot|eCatalog|eMedia);
if (c) debug("FsExtractCustomIconW(%S,%d)\n",Path,flags);
if (c&(eRoot|eCatalog)) {
ico=LoadIcon(hInstance,MAKEINTRESOURCE(1));
return FS_ICON_EXTRACTED;
}
if (c&eMedia) {
ico=LoadIcon(hInstance,MAKEINTRESOURCE(2));
return FS_ICON_EXTRACTED;
}
return FS_ICON_USEDEFAULT;
}
#if 0
int WINAPI FsExtractCustomIcon(char* RemoteName,int ExtractFlags,HICON* TheIcon)
{
WCHAR RemoteNameW[LONGPATH_MAX],OldNameW[LONGPATH_MAX];
unicopy(RemoteNameW,elemof(RemoteNameW),RemoteName);
lstrcpyW(OldNameW,RemoteNameW);
int retval=FsExtractCustomIconW(RemoteNameW,ExtractFlags,TheIcon);
if (lstrcmpW(OldNameW,RemoteNameW)!=0)
unicopy(RemoteName,sizeof RemoteName,RemoteNameW);
return retval;
}
int WINAPI FsGetPreviewBitmap(char* RemoteName,int width,int height,HBITMAP* ReturnedBitmap) {
if (lstrlen(RemoteName)<=4) {
if (!lstrcmp(RemoteName,"\\..\\")) return FS_BITMAP_NONE;
// check for operating system: Windows 9x does NOT support the HALFTONE stretchblt mode!
bool is_nt=usys();
HBITMAP bmp_image=LoadBitmap((HINSTANCE)hInstance,"BITMAP1");
BITMAP bmpobj;
if (bmp_image && GetObject(bmp_image,sizeof(bmpobj),&bmpobj)) {
int bigx=bmpobj.bmWidth;
int bigy=bmpobj.bmHeight;
// do we need to stretch?
if ((bigx>=width || bigy>=height) && (bigx>0 && bigy>0)) {
int w,h,stretchx,stretchy=MulDiv(width,bigy,bigx);
if (stretchy<=height) {
w=width;
h=stretchy;
if (h<1) h=1;
}else{
stretchx=MulDiv(height,bigx,bigy);
w=stretchx;
if (w<1) w=1;
h=height;
}
HDC maindc=GetDC(GetDesktopWindow());
HDC dc_thumbnail=CreateCompatibleDC(maindc);
HDC dc_image=CreateCompatibleDC(maindc);
HBITMAP bmp_thumbnail=CreateCompatibleBitmap(maindc,w,h);
ReleaseDC(GetDesktopWindow(),maindc);
HBITMAP oldbmp_image=(HBITMAP)SelectObject(dc_image,bmp_image);
HBITMAP oldbmp_thumbnail=(HBITMAP)SelectObject(dc_thumbnail,bmp_thumbnail);
if (is_nt) {
SetStretchBltMode(dc_thumbnail,HALFTONE);
SetBrushOrgEx(dc_thumbnail,0,0,0);
}else{
SetStretchBltMode(dc_thumbnail,COLORONCOLOR);
}
StretchBlt(dc_thumbnail,0,0,w,h,dc_image,0,0,bigx,bigy,SRCCOPY);
SelectObject(dc_image,oldbmp_image);
SelectObject(dc_thumbnail,oldbmp_thumbnail);
DeleteDC(dc_image);
DeleteDC(dc_thumbnail);
DeleteObject(bmp_image);
*ReturnedBitmap=bmp_thumbnail;
return FS_BITMAP_EXTRACTED;
}
*ReturnedBitmap=bmp_image;
return FS_BITMAP_EXTRACTED;
}
return FS_BITMAP_NONE;
}
memmove(RemoteName,RemoteName+pluginrootlen,lstrlen(RemoteName+pluginrootlen)+1);
return FS_BITMAP_EXTRACT_YOURSELF | FS_BITMAP_CACHE;
}
int WINAPI FsGetPreviewBitmapW(WCHAR* RemoteName,int width,int height,HBITMAP* ReturnedBitmap)
{
if (lstrlenW(RemoteName)<=4) {
if (lstrcmpW(RemoteName,L"\\..\\")==0)
return FS_BITMAP_NONE;
else {
return FsGetPreviewBitmap("\\",width,height,ReturnedBitmap);
}
} else {
memmove(RemoteName,RemoteName+pluginrootlen,2*lstrlenW(RemoteName+pluginrootlen)+2);
return FS_BITMAP_EXTRACT_YOURSELF | FS_BITMAP_CACHE;
}
}
#endif
void WINAPI FsSetDefaultParams(FsDefaultParamStruct* dps) {
lstrcpyn(inifilename,dps->DefaultIniName,elemof(inifilename));
char buf[4000],*p=buf;
GetPrivateProfileSection("cdcat1",buf,sizeof buf,inifilename);
// Als UTF-8 interpretieren
LoadedFile*lf=&loadedFiles[0];
for (int l;l=lstrlen(p);p+=l+1,lf++) {
char*q=StrChr(p,'=');
if (!q) continue;
size_t l1=q-p;
if (l1>sizeof lf->displayname-1) l1=sizeof lf->displayname-1;
memcpy(lf->displayname,p,l1);
lf->displayname[l1]=0;
l1 = l-l1; // Länge Dateiname inklusive '\0'
if (l1>sizeof lf->filename) l1=sizeof lf->filename;
memcpy(lf->filename,q+1,l1);
}
loadedFiles.size(int(lf-&loadedFiles[0]));
}
#if 0
BOOL WINAPI FsLinksToLocalFiles() {
return true;
}
BOOL WINAPI FsGetLocalName(char* RemoteName,int maxlen) {
if (lstrlen(RemoteName)<pluginrootlen+2) return false;
MoveMemory (RemoteName,RemoteName+pluginrootlen,lstrlen(RemoteName+pluginrootlen)+1);
return true;
}
BOOL WINAPI FsGetLocalNameW(WCHAR* RemoteName,int maxlen) {
if (lstrlenW(RemoteName)<pluginrootlen+2) return false;
MoveMemory(RemoteName,RemoteName+pluginrootlen,2*lstrlenW(RemoteName+pluginrootlen)+2);
return true;
}
/**************************************************************************************/
/*********************** content plugin = custom columns part! ************************/
/**************************************************************************************/
#define fieldcount 6
char* fieldnames[fieldcount]={
"size","creationdate","writedate","accessdate","size-delayed","size-ondemand"};
int fieldtypes[fieldcount]={
ft_numeric_64,ft_datetime,ft_datetime,ft_datetime,ft_numeric_64,ft_numeric_64};
char* fieldunits_and_multiplechoicestrings[fieldcount]={
"bytes|kbytes|Mbytes|Gbytes","","","","bytes|kbytes|Mbytes|Gbytes","bytes|kbytes|Mbytes|Gbytes"};
int fieldflags[fieldcount]={
contflags_substsize,contflags_edit,contflags_substdatetime,contflags_edit,contflags_substsize,contflags_substsize | contflags_edit};
int sortorders[fieldcount]={-1,-1,-1,-1,-1,-1};
int WINAPI FsContentGetSupportedField(int FieldIndex,char* FieldName,char* Units,int maxlen)
{
if (FieldIndex<0 || FieldIndex>=fieldcount)
return ft_nomorefields;
lstrcpyn(FieldName,fieldnames[FieldIndex],maxlen);
lstrcpyn(Units,fieldunits_and_multiplechoicestrings[FieldIndex],maxlen);
return fieldtypes[FieldIndex];
}
int WINAPI FsContentGetValueT(BOOL unicode,WCHAR* FileName,int FieldIndex,int UnitIndex,void* FieldValue,int maxlen,int flags) {
HANDLE fh;
ULONGLONG filesize;
if (lstrlenW(FileName+pluginrootlen)<=3) return ft_fileerror;
if (flags & CONTENT_DELAYIFSLOW) {
if (FieldIndex==4) return ft_delayed;
if (FieldIndex==5) return ft_ondemand;
}
WIN32_FIND_DATAW W;
fh=FindFirstFileT(FileName+pluginrootlen,W);
if (fh!=INVALID_HANDLE_VALUE) {
FindClose(fh);
switch (FieldIndex) {
case 0: // "size"
case 4: // "size-delayed"
case 5: // "size-ondemand"
filesize=W.nFileSizeHigh;
filesize=(filesize<<32) + W.nFileSizeLow;
switch (UnitIndex) {
case 1:
filesize>>=10;
break;
case 2:
filesize>>=20;
break;
case 3:
filesize>>=30;
break;
}
*(ULONGLONG*)FieldValue=filesize;
break;
case 1: // "creationdate"
*(FILETIME*)FieldValue=W.ftCreationTime;
break;
case 2: // "writedate"
*(FILETIME*)FieldValue=W.ftLastWriteTime;
break;
case 3: // "accessdate"
*(FILETIME*)FieldValue=W.ftLastAccessTime;
break;
default: return ft_nosuchfield;
}
}else return ft_fileerror;
return fieldtypes[FieldIndex]; // very important!
}
int WINAPI FsContentGetValueW(WCHAR* FileName,int FieldIndex,int UnitIndex,void* FieldValue,int maxlen,int flags) {
return FsContentGetValueT(true,FileName,FieldIndex,UnitIndex,FieldValue,maxlen,flags);
}
int WINAPI FsContentGetValue(char* FileName,int FieldIndex,int UnitIndex,void* FieldValue,int maxlen,int flags) {
WCHAR FileNameW[LONGPATH_MAX];
return FsContentGetValueT(false,unicopy(FileNameW,elemof(FileNameW),FileName),
FieldIndex,UnitIndex,FieldValue,maxlen,flags);
}
int WINAPI FsContentGetSupportedFieldFlags(int FieldIndex)
{
if (FieldIndex==-1)
return contflags_substmask | contflags_edit;
else if (FieldIndex<0 || FieldIndex>=fieldcount)
return 0;
else
return fieldflags[FieldIndex];
}
int WINAPI FsContentGetDefaultSortOrder(int FieldIndex)
{
if (FieldIndex<0 || FieldIndex>=fieldcount)
return 1;
else
return sortorders[FieldIndex];
}
BOOL WINAPI FsContentGetDefaultView(char* ViewContents,char* ViewHeaders,char* ViewWidths,char* ViewOptions,int maxlen)
{
lstrcpyn(ViewContents,"[=<fs>.size.bkM2]\\n[=tc.size.bkM2]",maxlen); // separated by backslash and n, not new lines!
lstrcpyn(ViewHeaders,"fs-size\\ntc-size",maxlen); // titles in ENGLISH also separated by backslash and n, not new lines!
lstrcpyn(ViewWidths,"148,23,-35,-35",maxlen);
lstrcpyn(ViewOptions,"-1|0",maxlen); // auto-adjust-width, or -1 for no adjust | horizonal scrollbar flag
return true;
}
int WINAPI FsContentSetValueW(WCHAR* FileName,int FieldIndex,int UnitIndex,int FieldType,void* FieldValue,int flags)
{
int retval=ft_nomorefields;
FILETIME oldcreationtime,newcreationtime;
FILETIME *p1,*p2,*FieldTime;
SYSTEMTIME st1,st2;
HANDLE f;
if (!FileName) return ft_nosuchfield; // indicates end of operation -> may be used to flush data
if (FieldIndex<0 || FieldIndex>=fieldcount) return ft_nosuchfield;
if (!(fieldflags[FieldIndex]&1)) return ft_nosuchfield;
switch (FieldIndex) {
case 1: // "creationdate"
case 3: // "accessdate"
FieldTime=(FILETIME*)FieldValue;
p1=NULL;p2=NULL;
if (FieldIndex==1)
p1=&oldcreationtime;
else
p2=&oldcreationtime;
f= CreateFileT(FileName+pluginrootlen,
GENERIC_READ|GENERIC_WRITE, // Open for reading+writing
0, // Do not share
NULL, // No security
OPEN_EXISTING, // Existing file only
FILE_ATTRIBUTE_NORMAL, // Normal file
NULL);
if (flags & setflags_only_date) {
GetFileTime(f,p1,p2,NULL);
FileTimeToLocalFileTime(&oldcreationtime,&newcreationtime);
FileTimeToSystemTime(&newcreationtime,&st2);
FileTimeToLocalFileTime(FieldTime,&newcreationtime);
FileTimeToSystemTime(&newcreationtime,&st1);
st1.wHour=st2.wHour;
st1.wMinute=st2.wMinute;
st1.wSecond=st2.wSecond;
st1.wMilliseconds=st2.wMilliseconds;
SystemTimeToFileTime(&st1,&newcreationtime);
LocalFileTimeToFileTime(&newcreationtime,&oldcreationtime);
} else
oldcreationtime=*FieldTime;
if (!SetFileTime(f,p1,p2,NULL))
retval=ft_fileerror;
CloseHandle(f);
break;
}
return retval;
}
int WINAPI FsContentSetValue(char* FileName,int FieldIndex,int UnitIndex,int FieldType,void* FieldValue,int flags) {
WCHAR FileNameW[LONGPATH_MAX];
return FsContentSetValueW(unicopy(FileNameW,elemof(FileNameW),FileName),
FieldIndex,UnitIndex,FieldType,FieldValue,flags);
}
void WINAPI FsContentPluginUnloading() {
// If you do something in a background thread, you may
// wait in this function until the thread has finished
// its work to prevent Total Commander from closing!
// MessageBox(0,"fsplugin unloading!","Test",0);
}
#endif
Detected encoding: UTF-8 | 0
|