aboutsummaryrefslogtreecommitdiff
path: root/src/base/io/CFileStream.cpp
blob: d5acc707c02149eb7a33cd96a3066e2e61c89dda (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
#include "cru/base/io/CFileStream.h"
#include "cru/base/Exception.h"
#include "cru/base/io/Stream.h"

#include <cstdio>

namespace cru::io {
static bool ModeCanRead(const char* mode) {
  for (const char* p = mode; *p != '\0'; p++) {
    if (*p == 'r' || *p == '+') {
      return true;
    }
  }
  return false;
}

static bool ModeCanWrite(const char* mode) {
  for (const char* p = mode; *p != '\0'; p++) {
    if (*p == 'w' || *p == 'a' || *p == '+') {
      return true;
    }
  }
  return false;
}

CFileStream::CFileStream(const char* path, const char* mode)
    : Stream(true, ModeCanRead(mode), ModeCanWrite(mode)),
      file_(std::fopen(path, mode)),
      auto_close_(true) {
  if (file_ == nullptr) {
    throw ErrnoException(u"Cannot open file.");
  }
}

CFileStream::CFileStream(std::FILE* file, bool readable, bool writable,
                         bool auto_close)
    : Stream(true, readable, writable), file_(file), auto_close_(auto_close) {
  if (file_ == nullptr) {
    throw Exception(u"File is NULL.");
  }
}

CFileStream::~CFileStream() {
  if (auto_close_ && file_ != nullptr) {
    std::fclose(file_);
  }
}

static int ConvertOriginFlag(Stream::SeekOrigin origin) {
  switch (origin) {
    case Stream::SeekOrigin::Begin:
      return SEEK_SET;
    case Stream::SeekOrigin::Current:
      return SEEK_CUR;
    case Stream::SeekOrigin::End:
      return SEEK_END;
    default:
      throw Exception(u"Unknown seek origin.");
  }
}

Index CFileStream::DoSeek(Index offset, SeekOrigin origin) {
  if (std::fseek(file_, offset, ConvertOriginFlag(origin))) {
    throw ErrnoException(u"Seek failed.");
  }
  return DoTell();
}

Index CFileStream::DoTell() {
  long position = std::ftell(file_);
  if (position == -1) {
    throw ErrnoException(u"Tell failed.");
  }
  return position;
}

void CFileStream::DoRewind() { std::rewind(file_); }

Index CFileStream::DoRead(std::byte* buffer, Index offset, Index size) {
  auto count = std::fread(buffer + offset, 1, size, file_);
  return count;
}

Index CFileStream::DoWrite(const std::byte* buffer, Index offset, Index size) {
  auto count = std::fwrite(buffer + offset, 1, size, file_);
  return count;
}

void CFileStream::DoFlush() { std::fflush(file_); }

void CFileStream::DoClose() {
  CRU_STREAM_BEGIN_CLOSE
  std::fclose(file_);
  file_ = nullptr;
}
}  // namespace cru::io