/* CVSNT Generic API Copyright (C) 2004 Tony Hoyle and March-Hare Software Ltd This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Win32 specific */ #define WIN32_LEAN_AND_MEAN #define STRICT #include #include #include #include #include "../lib/api_system.h" #include "../cvs_string.h" #include "../FileAccess.h" bool CFileAccess::m_bUtf8Mode = false; CFileAccess::CFileAccess() { m_file = NULL; } CFileAccess::~CFileAccess() { close(); } bool CFileAccess::open(const char *filename, const char *mode) { m_file = _wfopen(Win32Wide(filename),Win32Wide(mode)); if(!m_file) return false; return true; } bool CFileAccess::open(FILE *file) { if(m_file) return false; m_file = file; return true; } bool CFileAccess::isopen() { if(!m_file) return false; return true; } bool CFileAccess::close() { if(m_file) fclose(m_file); m_file = NULL; return true; } bool CFileAccess::getline(cvs::string& line) { int c; if(!m_file) return false; line.reserve(256); line=""; while((c=fgetc(m_file))!=EOF) { if(c=='\n') break; if(c=='\r') continue; line.append(1,c); } if(c==EOF && line.empty()) return false; return true; } bool CFileAccess::getline(char *line, size_t length) { int c; size_t len = length; if(!m_file) return false; while(len && (c=fgetc(m_file))!=EOF) { if(c=='\n') break; *(line++)=(char)c; --len; } if(c==EOF && len==length) return false; return true; } bool CFileAccess::putline(const char *line) { if(!m_file) return false; if(fwrite(line,1,strlen(line),m_file)0x7FFFFFFF) { if(fseek(m_file,0x7FFFFFFF,whence)<0) return false; pos-=0x7FFFFFFFF; while(pos>0x7FFFFFFF && !fseek(m_file,-0x7FFFFFFF,SEEK_CUR)) pos-=0x7FFFFFFFF; if(pos>0x7FFFFFFF) return false; pos=-pos; } if(fseek(m_file,(long)pos,SEEK_CUR)<0) return false; return true; default: return false; } if(fsetpos(m_file,&p)<0) return false; return true; } cvs::wstring CFileAccess::wtempdir() { cvs::wstring dir; DWORD fa; dir.resize(MAX_PATH); if(!GetEnvironmentVariableW(_T("TEMP"),(TCHAR*)dir.data(),(DWORD)dir.size()) && !GetEnvironmentVariableW(_T("TMP"),(TCHAR*)dir.data(),(DWORD)dir.size())) { // No TEMP or TMP, use default \TEMP GetWindowsDirectoryW((wchar_t*)dir.data(),(UINT)dir.size()); wcscat((wchar_t*)dir.data(),L"\\TEMP"); } dir.resize(wcslen((wchar_t*)dir.data())); if((fa=GetFileAttributesW(dir.c_str()))==0xFFFFFFFF || !(fa&FILE_ATTRIBUTE_DIRECTORY)) { // Last resort, can't find a valid temp.... use C:\... dir=L"C:\\"; } return dir; } cvs::string CFileAccess::tempdir() { return (const char *)Win32Narrow(wtempdir().c_str()); } cvs::string CFileAccess::tempfilename(const char *prefix) { cvs::wstring tempfile; tempfile.resize(MAX_PATH); GetTempFileNameW(wtempdir().c_str(),Win32Wide(prefix),0,(wchar_t*)tempfile.data()); tempfile.resize(wcslen((wchar_t*)tempfile.data())); DeleteFileW(tempfile.c_str()); return (const char *)Win32Narrow(tempfile.c_str()); } bool CFileAccess::_remove(cvs::wstring& path) { WIN32_FIND_DATAW wfd; HANDLE hFind; hFind = FindFirstFileW((path+L"/*.*").c_str(),&wfd); if(hFind==INVALID_HANDLE_VALUE) return FALSE; do { if(wfd.cFileName[0]!='.' || (wfd.cFileName[1]!='.' && wfd.cFileName[1]!='\0')) { size_t l = path.length(); path+=L"/"; path+=wfd.cFileName; if(wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) { if(!_remove(path)) { FindClose(hFind); return false; } } else { if(wfd.dwFileAttributes&FILE_ATTRIBUTE_READONLY) SetFileAttributesW(path.c_str(),wfd.dwFileAttributes&~FILE_ATTRIBUTE_READONLY); if(!DeleteFile(path.c_str())) { FindClose(hFind); return false; } } path.resize(l); } } while(FindNextFile(hFind,&wfd)); FindClose(hFind); if(!RemoveDirectoryW(path.c_str())) return false; return true; } bool CFileAccess::remove(const char *file, bool recursive /* = false */) { Win32Wide wfile(file); DWORD att = GetFileAttributesW(wfile); if(att==0xFFFFFFFF) return false; SetFileAttributesW(wfile,att&~FILE_ATTRIBUTE_READONLY); if(att&FILE_ATTRIBUTE_DIRECTORY) { if(!recursive) { if(!RemoveDirectoryW(wfile)) return false; } else { cvs::wstring wpath = wfile; if(!_remove(wpath)) return false; } } else { if(!DeleteFileW(wfile)) return false; } return true; } bool CFileAccess::rename(const char *from, const char *to) { Win32Wide wfrom(from); Win32Wide wto(to); DWORD att = GetFileAttributesW(wfrom); if(att==0xFFFFFFFF) return false; SetFileAttributesW(wfrom,att&~FILE_ATTRIBUTE_READONLY); att = GetFileAttributesW(wto); if(att!=0xFFFFFFFF) SetFileAttributesW(wto,att&~FILE_ATTRIBUTE_READONLY); if(!MoveFileExW(wfrom,wto,MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING)) return false; return true; } void CFileAccess::Win32SetUtf8Mode(bool bUtf8Mode) { m_bUtf8Mode = bUtf8Mode; } CFileAccess::Win32Wide::Win32Wide(const char *fn) { if(!fn) { pbuf=NULL; return; } size_t l = strlen(fn)+1; if(l>(sizeof(buf)/sizeof(wchar_t))) pbuf=new wchar_t[l]; else pbuf=buf; MultiByteToWideChar(m_bUtf8Mode?CP_UTF8:CP_ACP,0,fn,(int)l,pbuf,(int)l*sizeof(wchar_t)); } CFileAccess::Win32Wide::~Win32Wide() { if(pbuf && pbuf!=buf) delete[] pbuf; } CFileAccess::Win32Narrow::Win32Narrow(const wchar_t *fn) { if(!fn) { pbuf=NULL; return; } size_t l = wcslen(fn)+1; if((l*3)>sizeof(buf)) pbuf=new char[l*3]; else pbuf=buf; WideCharToMultiByte(m_bUtf8Mode?CP_UTF8:CP_ACP,0,fn,(int)l,pbuf,(int)(l*3),NULL,NULL); } CFileAccess::Win32Narrow::~Win32Narrow() { if(pbuf && pbuf!=buf) delete[] pbuf; } bool CFileAccess::exists(const char *file) { if(GetFileAttributesW(Win32Wide(file))==0xFFFFFFFF) return false; return true; } CFileAccess::TypeEnum CFileAccess::type(const char *file) { DWORD dw = GetFileAttributesW(Win32Wide(file)); if(dw==0xFFFFFFFF) return typeNone; if(dw&FILE_ATTRIBUTE_DIRECTORY) return typeDirectory; return typeFile; } bool CFileAccess::absolute(const char *file) { return file[0]=='\\' || file[0]=='/' || file[1]==':'; } int CFileAccess::uplevel(const char *file) { int level = 0; for(const char *p=file; *p;) { size_t l=strcspn(p,"\\/"); if(l==1 && *p=='.') level++; // Compensate for ./ else if(l==2 && *p=='.' && *(p+1)=='.') level+=2; // Compensate for ../ p+=l; if(*p) p++; level--; } return level; } cvs::string CFileAccess::mimetype(const char *filename) { HKEY hk; const char *p = strrchr(filename,'.'); if(!p) return ""; if(RegOpenKeyEx(HKEY_CLASSES_ROOT,cvs::wide(p),0,KEY_QUERY_VALUE,&hk)) return ""; TCHAR str[256]; DWORD len = sizeof(str)-sizeof(TCHAR); if(RegQueryValueEx(hk,L"Content Type",NULL,NULL,(LPBYTE)str,&len)) { RegCloseKey(hk); return ""; } str[len]='\0'; return (const char *)cvs::narrow(str); }