////////////////////////////////////////////////////////////////////////////////
// Win32/File.cpp -- this file is part of the Emulator Developers Kit
// available at http://ourworld.compuserve.com/homepages/pc64/develop.htm


////////////////////////////////////////////////////////////////////////////////
// close the file

global void File::Close() {
  if (hFile != INVALID_HANDLE_VALUE) {
    if (!CloseHandle(hFile)) {
      error("File::Close() failed with %s\n%s", Name.c_str(), WinErrorString(GetLastError()));
    }
    hFile = INVALID_HANDLE_VALUE;
  }
}


////////////////////////////////////////////////////////////////////////////////
// set name and open the file

global void File::SetName(const char* pcNewName) {

  // close the old file
  Close();

  // save full path of the file name
  char acFullName[_MAX_PATH];
  win(GetFullPathName(pcNewName, sizeof acFullName, acFullName, NULL));
  Name = acFullName;

  // open the file with read/write permission
  if (!bReadOnly) {
    hFile = CreateFile(pcNewName, dwDesiredAccess, dwShareMode, NULL, dwCreationDistribution, dwFlagsAndAttributes, NULL);
    if (hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_ACCESS_DENIED) {
      bReadOnly = true;
    }
  }

  // open the file as read only
  if (bReadOnly) {
    assert(OPEN_EXISTING < 8);
    hFile = CreateFile(pcNewName, GENERIC_READ, dwShareMode, NULL, (dwCreationDistribution & ~7) | OPEN_EXISTING, dwFlagsAndAttributes, NULL);
  }

  // check for error
  if (hFile == INVALID_HANDLE_VALUE) {
    error("File::SetName() failed with %s\n%s", Name.c_str(), WinErrorString(GetLastError()));
  }
}


////////////////////////////////////////////////////////////////////////////////
// get size

global int File::GetSize() {
  int iSize = (int)GetFileSize(hFile, NULL);
  if (iSize == -1) {
    error("File::GetSize() failed with %s\n%s", Name.c_str(), WinErrorString(GetLastError()));
  }
  return iSize;
}


////////////////////////////////////////////////////////////////////////////////
// set size

global void File::SetSize(int iNewSize) {
  int iSavedPosition = GetPosition();
  SetPosition(iNewSize);
  if (!SetEndOfFile(hFile)) {
    error("File::SetSize(%d) failed with %s\n%s", iNewSize, Name.c_str(), WinErrorString(GetLastError()));
  }
  if (iSavedPosition > iNewSize) {
    iSavedPosition = iNewSize;
  }
  SetPosition(iSavedPosition);
}


////////////////////////////////////////////////////////////////////////////////
// get position

global int File::GetPosition() {
  int iPosition = (int)SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
  if (iPosition == -1) {
    error("File::GetPosition() failed with %s\n%s", Name.c_str(), WinErrorString(GetLastError()));
  }
  return iPosition;
}


////////////////////////////////////////////////////////////////////////////////
// set position

global void File::SetPosition(int iNewPosition) {
  if ((int)SetFilePointer(hFile, iNewPosition, NULL, FILE_BEGIN) == -1) {
    error("File::SetPosition(%d) failed with %s\n%s", iNewPosition, Name.c_str(), WinErrorString(GetLastError()));
  }
}


////////////////////////////////////////////////////////////////////////////////
// read data

global void File::Read(void* pBuffer, int iCount) {
  DWORD dwRead = 0;
  if (!ReadFile(hFile, pBuffer, iCount, &dwRead, NULL)) {
    error("File::Read() failed with %s\n%s", Name.c_str(), WinErrorString(GetLastError()));
  }
  if ((int)dwRead != iCount) {
    error("File::Read() failed with %s\n%s", Name.c_str(), WinErrorString(ERROR_HANDLE_EOF));
  }
}


////////////////////////////////////////////////////////////////////////////////
// write data

global void File::Write(const void* pBuffer, int iCount) {
  DWORD dwWritten = 0;
  if (!WriteFile(hFile, pBuffer, iCount, &dwWritten, NULL)) {
    error("File::Write() failed with %s\n%s", Name.c_str(), WinErrorString(GetLastError()));
  }
  if ((int)dwWritten != iCount) {
    error("File::Write() failed with %s\n%s", Name.c_str(), WinErrorString(ERROR_HANDLE_DISK_FULL));
  }
}
