Blob Blame Raw


#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<char *>(lpMsgBuf));
	LocalFree(lpMsgBuf);
	return s;
}