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