1 /**
2 * Copyright (c) 2006-2016 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21 // LOVE
22 #include "DroppedFile.h"
23 #include "common/utf8.h"
24
25 // Assume POSIX or Visual Studio.
26 #include <sys/types.h>
27 #include <sys/stat.h>
28
29 #ifdef LOVE_WINDOWS
30 #include <wchar.h>
31 #else
32 #include <unistd.h> // POSIX.
33 #endif
34
35 namespace love
36 {
37 namespace filesystem
38 {
39
DroppedFile(const std::string & filename)40 DroppedFile::DroppedFile(const std::string &filename)
41 : filename(filename)
42 , file(nullptr)
43 , mode(MODE_CLOSED)
44 , bufferMode(BUFFER_NONE)
45 , bufferSize(0)
46 {
47 }
48
~DroppedFile()49 DroppedFile::~DroppedFile()
50 {
51 if (mode != MODE_CLOSED)
52 close();
53 }
54
open(Mode newmode)55 bool DroppedFile::open(Mode newmode)
56 {
57 if (newmode == MODE_CLOSED)
58 return true;
59
60 // File already open?
61 if (file != nullptr)
62 return false;
63
64 #ifdef LOVE_WINDOWS
65 // make sure non-ASCII filenames work.
66 std::wstring modestr = to_widestr(getModeString(newmode));
67 std::wstring wfilename = to_widestr(filename);
68
69 file = _wfopen(wfilename.c_str(), modestr.c_str());
70 #else
71 file = fopen(filename.c_str(), getModeString(newmode));
72 #endif
73
74 if (newmode == MODE_READ && file == nullptr)
75 throw love::Exception("Could not open file %s. Does not exist.", filename.c_str());
76
77 mode = newmode;
78
79 if (file != nullptr && !setBuffer(bufferMode, bufferSize))
80 {
81 // Revert to buffer defaults if we don't successfully set the buffer.
82 bufferMode = BUFFER_NONE;
83 bufferSize = 0;
84 }
85
86 return file != nullptr;
87 }
88
close()89 bool DroppedFile::close()
90 {
91 if (file == nullptr || fclose(file) != 0)
92 return false;
93
94 mode = MODE_CLOSED;
95 file = nullptr;
96
97 return true;
98 }
99
isOpen() const100 bool DroppedFile::isOpen() const
101 {
102 return mode != MODE_CLOSED && file != nullptr;
103 }
104
getSize()105 int64 DroppedFile::getSize()
106 {
107 #ifdef LOVE_WINDOWS
108
109 // make sure non-ASCII filenames work.
110 std::wstring wfilename = to_widestr(filename);
111
112 struct _stat buf;
113 if (_wstat(wfilename.c_str(), &buf) != 0)
114 return -1;
115
116 return (int64) buf.st_size;
117
118 #else
119
120 // Assume POSIX support...
121 struct stat buf;
122 if (stat(filename.c_str(), &buf) != 0)
123 return -1;
124
125 return (int64) buf.st_size;
126
127 #endif
128 }
129
read(void * dst,int64 size)130 int64 DroppedFile::read(void *dst, int64 size)
131 {
132 if (!file || mode != MODE_READ)
133 throw love::Exception("File is not opened for reading.");
134
135 if (size < 0)
136 throw love::Exception("Invalid read size.");
137
138 size_t read = fread(dst, 1, (size_t) size, file);
139
140 return (int64) read;
141 }
142
write(const void * data,int64 size)143 bool DroppedFile::write(const void *data, int64 size)
144 {
145 if (!file || (mode != MODE_WRITE && mode != MODE_APPEND))
146 throw love::Exception("File is not opened for writing.");
147
148 if (size < 0)
149 throw love::Exception("Invalid write size.");
150
151 int64 written = (int64) fwrite(data, 1, (size_t) size, file);
152
153 return written == size;
154 }
155
flush()156 bool DroppedFile::flush()
157 {
158 if (!file || (mode != MODE_WRITE && mode != MODE_APPEND))
159 throw love::Exception("File is not opened for writing.");
160
161 return fflush(file) == 0;
162 }
163
isEOF()164 bool DroppedFile::isEOF()
165 {
166 return file == nullptr || feof(file) != 0;
167 }
168
tell()169 int64 DroppedFile::tell()
170 {
171 if (file == nullptr)
172 return -1;
173
174 return (int64) ftell(file);
175 }
176
seek(uint64 pos)177 bool DroppedFile::seek(uint64 pos)
178 {
179 return file != nullptr && fseek(file, (long) pos, SEEK_SET) == 0;
180 }
181
setBuffer(BufferMode bufmode,int64 size)182 bool DroppedFile::setBuffer(BufferMode bufmode, int64 size)
183 {
184 if (size < 0)
185 return false;
186
187 if (bufmode == BUFFER_NONE)
188 size = 0;
189
190 // If the file isn't open, we'll make sure the buffer values are set in
191 // DroppedFile::open.
192 if (!isOpen())
193 {
194 bufferMode = bufmode;
195 bufferSize = size;
196 return true;
197 }
198
199 int vbufmode;
200 switch (bufmode)
201 {
202 case File::BUFFER_NONE:
203 default:
204 vbufmode = _IONBF;
205 break;
206 case File::BUFFER_LINE:
207 vbufmode = _IOLBF;
208 break;
209 case File::BUFFER_FULL:
210 vbufmode = _IOFBF;
211 break;
212 }
213
214 if (setvbuf(file, nullptr, vbufmode, (size_t) size) != 0)
215 return false;
216
217 bufferMode = bufmode;
218 bufferSize = size;
219
220 return true;
221 }
222
getBuffer(int64 & size) const223 File::BufferMode DroppedFile::getBuffer(int64 &size) const
224 {
225 size = bufferSize;
226 return bufferMode;
227 }
228
getFilename() const229 const std::string &DroppedFile::getFilename() const
230 {
231 return filename;
232 }
233
getMode() const234 File::Mode DroppedFile::getMode() const
235 {
236 return mode;
237 }
238
getModeString(Mode mode)239 const char *DroppedFile::getModeString(Mode mode)
240 {
241 switch (mode)
242 {
243 case File::MODE_CLOSED:
244 default:
245 return "c";
246 case File::MODE_READ:
247 return "rb";
248 case File::MODE_WRITE:
249 return "wb";
250 case File::MODE_APPEND:
251 return "ab";
252 }
253 }
254
255 } // filesystem
256 } // love
257