1 // Copyright 2017-2018 the openage authors. See copying.md for legal info.
2
3 #include "native.h"
4
5 #include <sstream>
6
7 #include "../../error/error.h"
8
9
10 namespace openage {
11 namespace util {
12 namespace filelike {
13
Native(const std::string & path,mode_t mode)14 Native::Native(const std::string &path, mode_t mode)
15 :
16 path{path},
17 mode{mode} {
18
19 std::ios_base::openmode open_mode;
20
21 switch (this->mode) {
22 case mode_t::R:
23 open_mode = std::ios_base::in;
24 break;
25 case mode_t::W:
26 open_mode = std::ios_base::out;
27 break;
28 case mode_t::RW:
29 open_mode = std::ios_base::in | std::ios_base::out;
30 break;
31 case mode_t::A:
32 open_mode = std::ios_base::out | std::ios_base::ate;
33 break;
34 case mode_t::AR:
35 open_mode = std::ios_base::in | std::ios_base::out | std::ios_base::ate;
36 break;
37 default:
38 throw Error{ERR << "unknown open mode"};
39 }
40
41 // Open in binary mode to avoid stupid behaviour on Windows
42 open_mode |= std::ios_base::binary;
43
44 this->file.open(this->path, open_mode);
45
46 if (not this->file.is_open()) {
47 throw Error{ERR << "file not found: " << path};
48 }
49 }
50
51
~Native()52 Native::~Native() {}
53
54
read(ssize_t max)55 std::string Native::read(ssize_t max) {
56 // read whole file:
57 if (max < 0) {
58 std::string ret;
59
60 // get remaining size and prepare the string size
61 // to avoid resizing
62 size_t pos = this->file.tellg();
63 this->file.seekg(0, std::ios::end);
64 ret.reserve(static_cast<size_t>(this->file.tellg()) - pos);
65 this->file.seekg(pos, std::ios::beg);
66
67 ret.assign(std::istreambuf_iterator<char>(this->file),
68 std::istreambuf_iterator<char>());
69
70 return ret;
71 }
72 // read `max` bytes
73 else {
74 // create string with required size
75 std::string ret;
76 ret.resize(max);
77
78 // and read the data
79 this->file.read(&ret[0], max);
80 return ret;
81 }
82 }
83
84
read_to(void * buf,ssize_t max)85 size_t Native::read_to(void *buf, ssize_t max) {
86 this->file.readsome(reinterpret_cast<std::fstream::char_type *>(buf), max);
87 return this->file.gcount();
88 }
89
90
readable()91 bool Native::readable() {
92 return (this->mode == mode_t::R or
93 this->mode == mode_t::RW);
94 }
95
96
write(const std::string & data)97 void Native::write(const std::string &data) {
98 this->file.write(data.c_str(), data.size());
99 }
100
101
writable()102 bool Native::writable() {
103 return (this->mode == mode_t::W or
104 this->mode == mode_t::RW);
105 }
106
107
seek(ssize_t offset,seek_t how)108 void Native::seek(ssize_t offset, seek_t how) {
109 std::ios::seekdir where;
110
111 switch (how) {
112 case seek_t::SET:
113 where = std::ios::beg;
114 break;
115 case seek_t::CUR:
116 where = std::ios::cur;
117 break;
118 case seek_t::END:
119 where = std::ios::end;
120 break;
121 default:
122 throw Error{ERR << "invalid seek mode"};
123 }
124
125 this->file.seekg(offset, where);
126 }
127
128
seekable()129 bool Native::seekable() {
130 return true;
131 }
132
133
tell()134 size_t Native::tell() {
135 return this->file.tellg();
136 }
137
138
close()139 void Native::close() {
140 this->file.close();
141 }
142
143
flush()144 void Native::flush() {
145 this->file.flush();
146 }
147
148
get_size()149 ssize_t Native::get_size() {
150 // remember where we were
151 size_t pos = this->file.tellg();
152
153 // go to the end
154 this->file.seekg(0, std::ios::end);
155 ssize_t size = static_cast<ssize_t>(this->file.tellg());
156
157 // return to position
158 this->file.seekg(pos, std::ios::beg);
159
160 return size;
161 }
162
163
repr(std::ostream & stream)164 std::ostream &Native::repr(std::ostream &stream) {
165 stream << "Native(" << this->path << ")";
166 return stream;
167 }
168
169 }}} // openage::util::filelike
170