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