Mercurial > love-experiments
annotate src/modules/filesystem/physfs/File.cpp @ 1166:86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
| author | Bart van Strien <bart.bes+projects@gmail.com> |
|---|---|
| date | Sat, 15 Dec 2012 13:58:34 +0100 |
| parents | d8c70acb666e |
| children | b7f097053d74 |
| rev | line source |
|---|---|
| 1096 | 1 /** |
| 2 * Copyright (c) 2006-2012 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 #include "File.h" | |
| 22 | |
| 23 // STD | |
| 24 #include <cstring> | |
| 25 | |
| 26 // LOVE | |
| 27 #include "Filesystem.h" | |
| 28 #include "filesystem/FileData.h" | |
| 29 | |
| 30 namespace love | |
| 31 { | |
| 32 namespace filesystem | |
| 33 { | |
| 34 namespace physfs | |
| 35 { | |
| 36 | |
| 37 extern bool hack_setupWriteDirectory(); | |
| 38 | |
| 39 File::File(std::string filename) | |
| 40 : filename(filename) | |
| 41 , file(0) | |
| 42 , mode(filesystem::File::CLOSED) | |
| 43 { | |
| 44 } | |
| 45 | |
| 46 File::~File() | |
| 47 { | |
| 48 if (mode != CLOSED) | |
| 49 close(); | |
| 50 } | |
| 51 | |
| 52 bool File::open(Mode mode) | |
| 53 { | |
| 54 if (mode == CLOSED) | |
| 55 return true; | |
| 56 | |
| 57 // File must exist if read mode. | |
| 58 if ((mode == READ) && !PHYSFS_exists(filename.c_str())) | |
| 59 throw love::Exception("Could not open file %s. Does not exist.", filename.c_str()); | |
| 60 | |
| 61 // Check whether the write directory is set. | |
| 62 if ((mode == APPEND || mode == WRITE) && (PHYSFS_getWriteDir() == 0) && !hack_setupWriteDirectory()) | |
| 63 throw love::Exception("Could not set write directory."); | |
| 64 | |
| 65 // File already open? | |
| 66 if (file != 0) | |
| 67 return false; | |
| 68 | |
| 69 this->mode = mode; | |
| 70 | |
| 71 switch (mode) | |
| 72 { | |
| 73 case READ: | |
| 74 file = PHYSFS_openRead(filename.c_str()); | |
| 75 break; | |
| 76 case APPEND: | |
| 77 file = PHYSFS_openAppend(filename.c_str()); | |
| 78 break; | |
| 79 case WRITE: | |
| 80 file = PHYSFS_openWrite(filename.c_str()); | |
| 81 break; | |
| 82 default: | |
| 83 break; | |
| 84 } | |
| 85 | |
| 86 return (file != 0); | |
| 87 } | |
| 88 | |
| 89 bool File::close() | |
| 90 { | |
| 91 if (!PHYSFS_close(file)) | |
| 92 return false; | |
| 93 mode = CLOSED; | |
| 94 file = 0; | |
| 95 return true; | |
| 96 } | |
| 97 | |
| 98 int64 File::getSize() | |
| 99 { | |
| 100 // If the file is closed, open it to | |
| 101 // check the size. | |
| 102 if (file == 0) | |
| 103 { | |
| 104 open(READ); | |
| 105 int64 size = (int64)PHYSFS_fileLength(file); | |
| 106 close(); | |
| 107 return size; | |
| 108 } | |
| 109 | |
| 110 return (int64)PHYSFS_fileLength(file); | |
| 111 } | |
| 112 | |
| 113 | |
|
1140
d8c70acb666e
Make love.sound.newDecoder accept FileData, and make File->read return FileData
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1096
diff
changeset
|
114 FileData *File::read(int64 size) |
| 1096 | 115 { |
| 116 bool isOpen = (file != 0); | |
| 117 | |
| 118 if (!isOpen && !open(READ)) | |
| 119 throw love::Exception("Could not read file %s.", filename.c_str()); | |
| 120 | |
|
1166
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
121 int64 max = getSize(); |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
122 int64 cur = tell(); |
| 1096 | 123 size = (size == ALL) ? max : size; |
|
1166
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
124 |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
125 // Clamping because the file offset may be in a weird position. |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
126 if (cur < 0) |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
127 cur = 0; |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
128 else if (cur > max) |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
129 cur = max; |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
130 |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
131 if (cur + size > max) |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
132 size = max - cur; |
| 1096 | 133 |
| 134 FileData *fileData = new FileData(size, getFilename()); | |
|
1166
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
135 int64 bytesRead = read(fileData->getData(), size); |
| 1096 | 136 |
|
1166
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
137 if (bytesRead < 0 || (bytesRead == 0 && bytesRead != size)) |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
138 { |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
139 delete fileData; |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
140 throw love::Exception("Could not read from file."); |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
141 } |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
142 if (bytesRead < size) |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
143 { |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
144 FileData *tmpFileData = new FileData(bytesRead, getFilename()); |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
145 memcpy(tmpFileData->getData(), fileData->getData(), (size_t) bytesRead); |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
146 delete fileData; |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
147 fileData = tmpFileData; |
|
86908814f2d8
Apply patch that fixes File:read from reading too much (on EOF) (bug #530)
Bart van Strien <bart.bes+projects@gmail.com>
parents:
1140
diff
changeset
|
148 } |
| 1096 | 149 |
| 150 if (!isOpen) | |
| 151 close(); | |
| 152 | |
| 153 return fileData; | |
| 154 } | |
| 155 | |
| 156 int64 File::read(void *dst, int64 size) | |
| 157 { | |
| 158 bool isOpen = (file != 0); | |
| 159 | |
| 160 if (!isOpen) | |
| 161 open(READ); | |
| 162 | |
| 163 int64 max = (int64)PHYSFS_fileLength(file); | |
| 164 size = (size == ALL) ? max : size; | |
| 165 size = (size > max) ? max : size; | |
| 166 // Sadly, we'll have to clamp to 32 bits here | |
| 167 size = (size > LOVE_UINT32_MAX) ? LOVE_UINT32_MAX : size; | |
| 168 | |
| 169 int64 read = (int64)PHYSFS_read(file, dst, 1, (int) size); | |
| 170 | |
| 171 if (!isOpen) | |
| 172 close(); | |
| 173 | |
| 174 return read; | |
| 175 } | |
| 176 | |
| 177 bool File::write(const void *data, int64 size) | |
| 178 { | |
| 179 if (file == 0) | |
| 180 throw love::Exception("Could not write to file. File not open."); | |
| 181 | |
| 182 // Another clamp, for the time being. | |
| 183 size = (size > LOVE_UINT32_MAX) ? LOVE_UINT32_MAX : size; | |
| 184 | |
| 185 // Try to write. | |
| 186 int64 written = static_cast<int64>(PHYSFS_write(file, data, 1, (int) size)); | |
| 187 | |
| 188 // Check that correct amount of data was written. | |
| 189 if (written != size) | |
| 190 return false; | |
| 191 | |
| 192 return true; | |
| 193 } | |
| 194 | |
| 195 bool File::write(const Data *data, int64 size) | |
| 196 { | |
| 197 return write(data->getData(), (size == ALL) ? data->getSize() : size); | |
| 198 } | |
| 199 | |
| 200 #ifdef LOVE_WINDOWS | |
| 201 // MSVC doesn't like the 'this' keyword | |
| 202 // well, we'll use 'that'. | |
| 203 // It zigs, we zag. | |
| 204 inline bool test_eof(File *that, PHYSFS_File *) | |
| 205 { | |
| 206 int64 pos = that->tell(); | |
| 207 int64 size = that->getSize(); | |
| 208 return pos == -1 || size == -1 || pos >= size; | |
| 209 } | |
| 210 #else | |
| 211 inline bool test_eof(File *, PHYSFS_File *file) | |
| 212 { | |
| 213 return PHYSFS_eof(file); | |
| 214 } | |
| 215 #endif | |
| 216 | |
| 217 bool File::eof() | |
| 218 { | |
| 219 if (file == 0 || test_eof(this, file)) | |
| 220 return true; | |
| 221 return false; | |
| 222 } | |
| 223 | |
| 224 int64 File::tell() | |
| 225 { | |
| 226 if (file == 0) | |
| 227 return -1; | |
| 228 | |
| 229 return (int64)PHYSFS_tell(file); | |
| 230 } | |
| 231 | |
| 232 bool File::seek(uint64 pos) | |
| 233 { | |
| 234 if (file == 0) | |
| 235 return false; | |
| 236 | |
| 237 if (!PHYSFS_seek(file, (PHYSFS_uint64)pos)) | |
| 238 return false; | |
| 239 return true; | |
| 240 } | |
| 241 | |
| 242 std::string File::getFilename() const | |
| 243 { | |
| 244 return filename; | |
| 245 } | |
| 246 | |
| 247 std::string File::getExtension() const | |
| 248 { | |
| 249 std::string::size_type idx = filename.rfind('.'); | |
| 250 | |
| 251 if (idx != std::string::npos) | |
| 252 return filename.substr(idx+1); | |
| 253 else | |
| 254 return std::string(); | |
| 255 } | |
| 256 | |
| 257 filesystem::File::Mode File::getMode() | |
| 258 { | |
| 259 return mode; | |
| 260 } | |
| 261 | |
| 262 } // physfs | |
| 263 } // filesystem | |
| 264 } // love |
