aboutsummaryrefslogtreecommitdiff
path: root/src/common/io/Win32FileStream.cpp
blob: e7ee0e6ab8e5860ba80d499458e3425beb9e0b3e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "cru/common/io/Win32FileStream.hpp"

#include "cru/common/Exception.hpp"
#include "cru/common/io/OpenFileFlag.hpp"

#include <Windows.h>

namespace cru::io {
namespace details {
struct Win32FileStreamPrivate {
  HANDLE handle;
};
}  // namespace details

Win32FileStream::Win32FileStream(String path, OpenFileFlag flags)
    : path_(std::move(path)), flags_(flags) {
  p_ = new details::Win32FileStreamPrivate();

  DWORD dwDesiredAccess = 0;
  if (flags & OpenFileFlags::Read) {
    dwDesiredAccess |= GENERIC_READ;
  }
  if (flags & OpenFileFlags::Write) {
    dwDesiredAccess |= GENERIC_WRITE;
  }

  DWORD dwCreationDisposition = 0;
  if (flags & OpenFileFlags::Create) {
    if (flags & OpenFileFlags::ThrowOnExist) {
      dwCreationDisposition = CREATE_NEW;
    } else {
      dwCreationDisposition = OPEN_ALWAYS;
    }
  } else {
    dwCreationDisposition = OPEN_EXISTING;
  }

  p_->handle =
      ::CreateFileW(path_.WinCStr(), dwDesiredAccess, 0, nullptr,
                    dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr);

  if (p_->handle == INVALID_HANDLE_VALUE) {
    throw Exception(u"Failed to call CreateFileW.");
  }
}

Win32FileStream::~Win32FileStream() {
  Close();
  delete p_;
}

bool Win32FileStream::CanSeek() { return true; }

Index Win32FileStream::Tell() {
  CheckClosed();

  LARGE_INTEGER offset;
  offset.QuadPart = 0;
  LARGE_INTEGER file_pointer;
  if (::SetFilePointerEx(p_->handle, offset, &file_pointer, FILE_CURRENT) ==
      0) {
    throw Exception(u"Failed to call SetFilePointerEx.");
  }

  return file_pointer.QuadPart;
}

void Win32FileStream::Seek(Index offset, SeekOrigin origin) {
  CheckClosed();

  DWORD dwMoveMethod = 0;

  if (origin == SeekOrigin::Current) {
    dwMoveMethod = FILE_CURRENT;
  } else if (origin == SeekOrigin::End) {
    dwMoveMethod = FILE_END;
  } else {
    dwMoveMethod = FILE_BEGIN;
  }

  LARGE_INTEGER n_offset;
  n_offset.QuadPart = offset;
  if (::SetFilePointerEx(p_->handle, n_offset, nullptr, dwMoveMethod) == 0) {
    throw Exception(u"Failed to call SetFilePointerEx.");
  }
}

bool Win32FileStream::CanRead() { return true; }

Index Win32FileStream::Read(std::byte* buffer, Index offset, Index size) {
  CheckClosed();

  DWORD dwRead;
  if (::ReadFile(p_->handle, buffer + offset, size, &dwRead, nullptr) == 0) {
    throw Exception(u"Failed to call ReadFile.");
  }
  return dwRead;
}

bool Win32FileStream::CanWrite() { return true; }

Index Win32FileStream::Write(const std::byte* buffer, Index offset,
                             Index size) {
  CheckClosed();

  DWORD dwWritten;
  if (::WriteFile(p_->handle, buffer + offset, size, &dwWritten, nullptr) ==
      0) {
    throw Exception(u"Failed to call WriteFile.");
  }

  return dwWritten;
}

void Win32FileStream::Close() {
  if (closed_) return;

  ::CloseHandle(p_->handle);

  closed_ = true;
}

void Win32FileStream::CheckClosed() {
  if (closed_) throw Exception(u"Stream is closed.");
}

}  // namespace cru::io