| |
| |
| #include "tfile.h" |
| |
| |
| |
| |
| |
| |
| |
| |
| using namespace TFileConsts; |
| |
| TFile::TFile(const TFilePath &fname, uint32 flags) : m_hFile(NULL), m_ec(0) { |
| open_internal(fname, flags); |
| } |
| |
| |
| |
| TFile::~TFile() { close(); } |
| |
| |
| |
| bool TFile::open(const TFilePath &fname, uint32 flags) { |
| return open_internal(fname, flags); |
| } |
| |
| |
| |
| bool TFile::open_internal(const TFilePath &fname, |
| uint32 flags) { |
| close(); |
| |
| |
| assert(flags & (kRead | kWrite)); |
| |
| DWORD dwDesiredAccess = 0; |
| |
| if (flags & kRead) dwDesiredAccess = GENERIC_READ; |
| if (flags & kWrite) dwDesiredAccess |= GENERIC_WRITE; |
| |
| |
| |
| |
| DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; |
| if (flags & kDenyRead) dwShareMode = FILE_SHARE_WRITE; |
| if (flags & kDenyWrite) dwShareMode &= ~FILE_SHARE_WRITE; |
| |
| |
| 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; |
| |
| |
| |
| |
| |
| m_hFile = |
| CreateFileW(fname.getWideString().c_str(), dwDesiredAccess, dwShareMode, |
| NULL, dwCreationDisposition, dwAttributes, NULL); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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; |
| |
| |
| |
| |
| |
| |
| |
| } |
| |
| 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) |
| |
| { |
| 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), |
| (LPTSTR)&lpMsgBuf, 0, NULL); |
| string s = string(reinterpret_cast<char *>(lpMsgBuf)); |
| LocalFree(lpMsgBuf); |
| return s; |
| } |
| |