#include "tfile.h" /* namespace { bool IsWindowsNT() { return (LONG)GetVersion()>=0; } }; */ using namespace TFileConsts; TFile::TFile(const TFilePath &fname, uint32 flags) : m_hFile(NULL), m_ec(0) { open_internal(fname, /*NULL,*/ flags); } //------------------------------------------------------------------------------ TFile::~TFile() { close(); } //------------------------------------------------------------------------------ bool TFile::open(const TFilePath &fname, uint32 flags) { return open_internal(fname, flags); } //------------------------------------------------------------------------------ bool TFile::open_internal(const TFilePath &fname, /*const wchar_t *pwszFilename,*/ uint32 flags) { close(); // At least one of the read/write flags must be set. assert(flags & (kRead | kWrite)); DWORD dwDesiredAccess = 0; if (flags & kRead) dwDesiredAccess = GENERIC_READ; if (flags & kWrite) dwDesiredAccess |= GENERIC_WRITE; // Win32 docs are screwed here -- FILE_SHARE_xxx is the inverse of a deny // flag. DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; if (flags & kDenyRead) dwShareMode = FILE_SHARE_WRITE; if (flags & kDenyWrite) dwShareMode &= ~FILE_SHARE_WRITE; // One of the creation flags must be set. assert(flags & kCreationMask); DWORD dwCreationDisposition; uint32 creationType = flags & kCreationMask; switch (creationType) { case kOpenExisting: dwCreationDisposition = OPEN_EXISTING; break; case kOpenAlways: dwCreationDisposition = OPEN_ALWAYS; break; case kCreateAlways: dwCreationDisposition = CREATE_ALWAYS; break; case kCreateNew: dwCreationDisposition = CREATE_NEW; break; case kTruncateExisting: dwCreationDisposition = TRUNCATE_EXISTING; break; default: assert(0); return false; } assert((flags & (kSequential | kRandomAccess)) != (kSequential | kRandomAccess)); DWORD dwAttributes = FILE_ATTRIBUTE_NORMAL; if (flags & kSequential) dwAttributes |= FILE_FLAG_SEQUENTIAL_SCAN; if (flags & kRandomAccess) dwAttributes |= FILE_FLAG_RANDOM_ACCESS; if (flags & kWriteThrough) dwAttributes |= FILE_FLAG_WRITE_THROUGH; if (flags & kUnbuffered) dwAttributes |= FILE_FLAG_NO_BUFFERING; /* if (pwszFilename && !IsWindowsNT()) pszFilename = VDFastTextWToA(pwszFilename); */ // if (pszFilename) m_hFile = CreateFileW(fname.getWideString().c_str(), dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); /* else m_hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); */ // VDFastTextFree(); // INVALID_HANDLE_VALUE isn't NULL. *sigh* if (m_hFile == INVALID_HANDLE_VALUE) { m_hFile = NULL; m_ec = GetLastError(); if (m_ec == ERROR_FILE_NOT_FOUND) return false; if (m_ec == ERROR_PATH_NOT_FOUND && creationType == kOpenExisting) return false; /* VDStringA fname(TFileSplitPathRight(pszFilename?VDString(pszFilename):VDTextWToA(VDStringW(pwszFilename)))); throw MyWin32Error("Cannot open file \"%s\":\n%%s", err, fname.c_str()); */ } m_FilePosition = 0; return true; } //------------------------------------------------------------------------------ bool TFile::close() { if (m_hFile) { HANDLE h = m_hFile; m_hFile = NULL; if (!CloseHandle(h)) { m_ec = GetLastError(); return false; } } return true; } //------------------------------------------------------------------------------ bool TFile::truncate() { DWORD rc = SetEndOfFile(m_hFile); if (rc) m_ec = GetLastError(); return 0 != rc; } //------------------------------------------------------------------------------ TINT32 TFile::read(void *buffer, TINT32 length) { DWORD dwActual; if (!ReadFile(m_hFile, buffer, (DWORD)length, &dwActual, NULL)) { m_ec = GetLastError(); return 0; } m_FilePosition += dwActual; return dwActual; } //------------------------------------------------------------------------------ TINT32 TFile::write(const void *buffer, TINT32 length) { DWORD dwActual; if (!WriteFile(m_hFile, buffer, (DWORD)length, &dwActual, NULL) || dwActual != (DWORD)length) { m_ec = GetLastError(); return 0; } m_FilePosition += dwActual; return dwActual; } //------------------------------------------------------------------------------ bool TFile::seek(TINT64 newPos, SeekMode mode) { DWORD dwMode; switch (mode) { case seekStart: dwMode = FILE_BEGIN; break; case seekCur: dwMode = FILE_CURRENT; break; case seekEnd: dwMode = FILE_END; break; default: assert(0); return false; } union { TINT64 pos; LONG l[2]; } u = {newPos}; u.l[0] = SetFilePointer(m_hFile, u.l[0], &u.l[1], dwMode); if (u.l[0] == -1 && GetLastError() != NO_ERROR) { m_ec = GetLastError(); return false; } m_FilePosition = u.pos; return true; } //------------------------------------------------------------------------------ bool TFile::skip(TINT64 delta) { if (!delta) return true; char buf[1024]; if (delta <= sizeof buf) return (TINT32)delta == read(buf, (TINT32)delta); else return seek(delta, seekCur); } //------------------------------------------------------------------------------ TINT64 TFile::size() { union { UINT64 siz; DWORD l[2]; } u; u.l[0] = GetFileSize(m_hFile, &u.l[1]); DWORD err; if (u.l[0] == (DWORD)-1L && (err = GetLastError()) != NO_ERROR) // throw MyWin32Error("Error retrieving file size: %%s", err); { m_ec = GetLastError(); return (TINT64)(-1); } return (TINT64)u.siz; } //------------------------------------------------------------------------------ TINT64 TFile::tell() { return m_FilePosition; } //------------------------------------------------------------------------------ bool TFile::isOpen() { return m_hFile != 0; } //------------------------------------------------------------------------------ string TFile::getLastError() { LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, m_ec, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR)&lpMsgBuf, 0, NULL); string s = string(reinterpret_cast(lpMsgBuf)); LocalFree(lpMsgBuf); return s; }