1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "common/archive.h"
24 #include "common/debug.h"
25 #include "common/file.h"
26 #include "common/fs.h"
27 #include "common/textconsole.h"
28 #include "common/system.h"
29 #include "backends/fs/fs-factory.h"
30
31 namespace Common {
32
File()33 File::File()
34 : _handle(nullptr) {
35 }
36
~File()37 File::~File() {
38 close();
39 }
40
open(const String & filename)41 bool File::open(const String &filename) {
42 return open(filename, SearchMan);
43 }
44
open(const String & filename,Archive & archive)45 bool File::open(const String &filename, Archive &archive) {
46 assert(!filename.empty());
47 assert(!_handle);
48
49 SeekableReadStream *stream = nullptr;
50
51 if ((stream = archive.createReadStreamForMember(filename))) {
52 debug(8, "Opening hashed: %s", filename.c_str());
53 } else if ((stream = archive.createReadStreamForMember(filename + "."))) {
54 // WORKAROUND: Bug #1458388: "SIMON1: Game Detection fails"
55 // sometimes instead of "GAMEPC" we get "GAMEPC." (note trailing dot)
56 debug(8, "Opening hashed: %s.", filename.c_str());
57 }
58
59 return open(stream, filename);
60 }
61
open(const FSNode & node)62 bool File::open(const FSNode &node) {
63 assert(!_handle);
64
65 if (!node.exists()) {
66 warning("File::open: '%s' does not exist", node.getPath().c_str());
67 return false;
68 } else if (node.isDirectory()) {
69 warning("File::open: '%s' is a directory", node.getPath().c_str());
70 return false;
71 }
72
73 SeekableReadStream *stream = node.createReadStream();
74 return open(stream, node.getPath());
75 }
76
open(SeekableReadStream * stream,const String & name)77 bool File::open(SeekableReadStream *stream, const String &name) {
78 assert(!_handle);
79
80 if (stream) {
81 _handle = stream;
82 _name = name;
83 } else {
84 debug(2, "File::open: opening '%s' failed", name.c_str());
85 }
86 return _handle != nullptr;
87 }
88
89
exists(const String & filename)90 bool File::exists(const String &filename) {
91 if (SearchMan.hasFile(filename)) {
92 return true;
93 } else if (SearchMan.hasFile(filename + ".")) {
94 // WORKAROUND: Bug #1458388: "SIMON1: Game Detection fails"
95 // sometimes instead of "GAMEPC" we get "GAMEPC." (note trailing dot)
96 return true;
97 }
98
99 return false;
100 }
101
close()102 void File::close() {
103 delete _handle;
104 _handle = nullptr;
105 }
106
isOpen() const107 bool File::isOpen() const {
108 return _handle != nullptr;
109 }
110
err() const111 bool File::err() const {
112 assert(_handle);
113 return _handle->err();
114 }
115
clearErr()116 void File::clearErr() {
117 assert(_handle);
118 _handle->clearErr();
119 }
120
eos() const121 bool File::eos() const {
122 assert(_handle);
123 return _handle->eos();
124 }
125
pos() const126 int32 File::pos() const {
127 assert(_handle);
128 return _handle->pos();
129 }
130
size() const131 int32 File::size() const {
132 assert(_handle);
133 return _handle->size();
134 }
135
seek(int32 offs,int whence)136 bool File::seek(int32 offs, int whence) {
137 assert(_handle);
138 return _handle->seek(offs, whence);
139 }
140
read(void * ptr,uint32 len)141 uint32 File::read(void *ptr, uint32 len) {
142 assert(_handle);
143 return _handle->read(ptr, len);
144 }
145
146
DumpFile()147 DumpFile::DumpFile() : _handle(nullptr) {
148 }
149
~DumpFile()150 DumpFile::~DumpFile() {
151 close();
152 }
153
open(const String & filename,bool createPath)154 bool DumpFile::open(const String &filename, bool createPath) {
155 assert(!filename.empty());
156 assert(!_handle);
157
158 if (createPath) {
159 for (uint32 i = 0; i < filename.size(); ++i) {
160 if (filename[i] == '/' || filename[i] == '\\') {
161 Common::String subpath = filename;
162 subpath.erase(i);
163 if (subpath.empty()) continue;
164 AbstractFSNode *node = g_system->getFilesystemFactory()->makeFileNodePath(subpath);
165 if (node->exists()) {
166 delete node;
167 continue;
168 }
169 if (!node->createDirectory()) warning("DumpFile: unable to create directories from path prefix");
170 delete node;
171 }
172 }
173 }
174
175 FSNode node(filename);
176 return open(node);
177 }
178
open(const FSNode & node)179 bool DumpFile::open(const FSNode &node) {
180 assert(!_handle);
181
182 if (node.isDirectory()) {
183 warning("DumpFile::open: FSNode is a directory");
184 return false;
185 }
186
187 _handle = node.createWriteStream();
188
189 if (_handle == nullptr)
190 debug(2, "File %s not found", node.getName().c_str());
191
192 return _handle != nullptr;
193 }
194
close()195 void DumpFile::close() {
196 delete _handle;
197 _handle = nullptr;
198 }
199
isOpen() const200 bool DumpFile::isOpen() const {
201 return _handle != nullptr;
202 }
203
err() const204 bool DumpFile::err() const {
205 assert(_handle);
206 return _handle->err();
207 }
208
clearErr()209 void DumpFile::clearErr() {
210 assert(_handle);
211 _handle->clearErr();
212 }
213
write(const void * ptr,uint32 len)214 uint32 DumpFile::write(const void *ptr, uint32 len) {
215 assert(_handle);
216 return _handle->write(ptr, len);
217 }
218
flush()219 bool DumpFile::flush() {
220 assert(_handle);
221 return _handle->flush();
222 }
223
pos() const224 int32 DumpFile::pos() const { return _handle->pos(); }
225
seek(int32 offset,int whence)226 bool DumpFile::seek(int32 offset, int whence) {
227 SeekableWriteStream *ws = dynamic_cast<SeekableWriteStream *>(_handle);
228 return ws ? ws->seek(offset, whence) : false;
229 }
230
size() const231 int32 DumpFile::size() const {
232 SeekableWriteStream *ws = dynamic_cast<SeekableWriteStream *>(_handle);
233 return ws ? ws->size() : -1;
234 }
235
236 } // End of namespace Common
237