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