Otclient  14/8/2020
filestream.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2020 OTClient <https://github.com/edubart/otclient>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 #include "filestream.h"
24 #include "binarytree.h"
26 
27 #include <physfs.h>
28 
29 FileStream::FileStream(const std::string& name, PHYSFS_File *fileHandle, bool writeable) :
30  m_name(name),
31  m_fileHandle(fileHandle),
32  m_pos(0),
33  m_writeable(writeable),
34  m_caching(false)
35 {
36 }
37 
38 FileStream::FileStream(const std::string& name, const std::string& buffer) :
39  m_name(name),
40  m_fileHandle(nullptr),
41  m_pos(0),
42  m_writeable(false),
43  m_caching(true)
44 {
45  m_data.resize(buffer.length());
46  memcpy(&m_data[0], &buffer[0], buffer.length());
47 }
48 
50 {
51 #ifndef NDEBUG
52  assert(!g_app.isTerminated());
53 #endif
54  if(!g_app.isTerminated())
55  close();
56 }
57 
59 {
60  m_caching = true;
61 
62  if(!m_writeable) {
63  if(!m_fileHandle)
64  return;
65 
66  // cache entire file into data buffer
67  m_pos = PHYSFS_tell(m_fileHandle);
68  PHYSFS_seek(m_fileHandle, 0);
69  int size = PHYSFS_fileLength(m_fileHandle);
70  m_data.resize(size);
71  if(PHYSFS_readBytes(m_fileHandle, m_data.data(), size) == -1)
72  throwError("unable to read file data", true);
73  PHYSFS_close(m_fileHandle);
74  m_fileHandle = nullptr;
75  }
76 }
77 
79 {
80  if(m_fileHandle && PHYSFS_isInit()) {
81  if(!PHYSFS_close(m_fileHandle))
82  throwError("close failed", true);
83  m_fileHandle = nullptr;
84  }
85 
86  m_data.clear();
87  m_pos = 0;
88 }
89 
91 {
92  if(!m_writeable)
93  throwError("filestream is not writeable");
94 
95  if(m_fileHandle) {
96  if(m_caching) {
97  if(!PHYSFS_seek(m_fileHandle, 0))
98  throwError("flush seek failed", true);
99  uint len = m_data.size();
100  if(PHYSFS_writeBytes(m_fileHandle, m_data.data(), len) != len)
101  throwError("flush write failed", true);
102  }
103 
104  if(PHYSFS_flush(m_fileHandle) == 0)
105  throwError("flush failed", true);
106  }
107 }
108 
109 int FileStream::read(void *buffer, uint32 size, uint32 nmemb)
110 {
111  if(!m_caching) {
112  int res = PHYSFS_readBytes(m_fileHandle, buffer, size * nmemb);
113  if(res == -1)
114  throwError("read failed", true);
115  return res;
116  } else {
117  int writePos = 0;
118  uint8 *outBuffer = (uint8*)buffer;
119  for(uint i=0;i<nmemb;++i) {
120  if(m_pos+size > m_data.size())
121  return i;
122 
123  for(uint j=0;j<size;++j)
124  outBuffer[writePos++] = m_data[m_pos++];
125  }
126  return nmemb;
127  }
128 }
129 
130 void FileStream::write(const void *buffer, uint32 count)
131 {
132  if(!m_caching) {
133  if(PHYSFS_writeBytes(m_fileHandle, buffer, count) != count)
134  throwError("write failed", true);
135  } else {
136  m_data.grow(m_pos + count);
137  memcpy(&m_data[m_pos], buffer, count);
138  m_pos += count;
139  }
140 }
141 
143 {
144  if(!m_caching) {
145  if(!PHYSFS_seek(m_fileHandle, pos))
146  throwError("seek failed", true);
147  } else {
148  if(pos > m_data.size())
149  throwError("seek failed");
150  m_pos = pos;
151  }
152 }
153 
155 {
156  seek(tell() + len);
157 }
158 
160 {
161  if(!m_caching)
162  return PHYSFS_fileLength(m_fileHandle);
163  else
164  return m_data.size();
165 }
166 
168 {
169  if(!m_caching)
170  return PHYSFS_tell(m_fileHandle);
171  else
172  return m_pos;
173 }
174 
176 {
177  if(!m_caching)
178  return PHYSFS_eof(m_fileHandle);
179  else
180  return m_pos >= m_data.size();
181 }
182 
184 {
185  uint8 v = 0;
186  if(!m_caching) {
187  if(PHYSFS_readBytes(m_fileHandle, &v, 1) != 1)
188  throwError("read failed", true);
189  } else {
190  if(m_pos+1 > m_data.size())
191  throwError("read failed");
192 
193  v = m_data[m_pos];
194  m_pos += 1;
195  }
196  return v;
197 }
198 
200 {
201  uint16 v = 0;
202  if(!m_caching) {
203  if(PHYSFS_readULE16(m_fileHandle, &v) == 0)
204  throwError("read failed", true);
205  } else {
206  if(m_pos+2 > m_data.size())
207  throwError("read failed");
208 
209  v = stdext::readULE16(&m_data[m_pos]);
210  m_pos += 2;
211  }
212  return v;
213 }
214 
216 {
217  uint32 v = 0;
218  if(!m_caching) {
219  if(PHYSFS_readULE32(m_fileHandle, &v) == 0)
220  throwError("read failed", true);
221  } else {
222  if(m_pos+4 > m_data.size())
223  throwError("read failed");
224 
225  v = stdext::readULE32(&m_data[m_pos]);
226  m_pos += 4;
227  }
228  return v;
229 }
230 
232 {
233  uint64 v = 0;
234  if(!m_caching) {
235  if(PHYSFS_readULE64(m_fileHandle, (PHYSFS_uint64*)&v) == 0)
236  throwError("read failed", true);
237  } else {
238  if(m_pos+8 > m_data.size())
239  throwError("read failed");
240  v = stdext::readULE64(&m_data[m_pos]);
241  m_pos += 8;
242  }
243  return v;
244 }
245 
247 {
248  int8 v = 0;
249  if(!m_caching) {
250  if(PHYSFS_readBytes(m_fileHandle, &v, 1) != 1)
251  throwError("read failed", true);
252  } else {
253  if(m_pos+1 > m_data.size())
254  throwError("read failed");
255 
256  v = m_data[m_pos];
257  m_pos += 1;
258  }
259  return v;
260 }
261 
263 {
264  int16 v = 0;
265  if(!m_caching) {
266  if(PHYSFS_readSLE16(m_fileHandle, &v) == 0)
267  throwError("read failed", true);
268  } else {
269  if(m_pos+2 > m_data.size())
270  throwError("read failed");
271 
272  v = stdext::readSLE16(&m_data[m_pos]);
273  m_pos += 2;
274  }
275  return v;
276 }
277 
279 {
280  int32 v = 0;
281  if(!m_caching) {
282  if(PHYSFS_readSLE32(m_fileHandle, &v) == 0)
283  throwError("read failed", true);
284  } else {
285  if(m_pos+4 > m_data.size())
286  throwError("read failed");
287 
288  v = stdext::readSLE32(&m_data[m_pos]);
289  m_pos += 4;
290  }
291  return v;
292 }
293 
295 {
296  int64 v = 0;
297  if(!m_caching) {
298  if(PHYSFS_readSLE64(m_fileHandle, (PHYSFS_sint64*)&v) == 0)
299  throwError("read failed", true);
300  } else {
301  if(m_pos+8 > m_data.size())
302  throwError("read failed");
303  v = stdext::readSLE64(&m_data[m_pos]);
304  m_pos += 8;
305  }
306  return v;
307 }
308 
310 {
311  std::string str;
312  uint16 len = getU16();
313  if(len > 0 && len < 8192) {
314  char buffer[8192];
315  if(m_fileHandle) {
316  if(PHYSFS_readBytes(m_fileHandle, buffer, len) == 0)
317  throwError("read failed", true);
318  else
319  str = std::string(buffer, len);
320  } else {
321  if(m_pos+len > m_data.size()) {
322  throwError("read failed");
323  return nullptr;
324  }
325 
326  str = std::string((char*)&m_data[m_pos], len);
327  m_pos += len;
328  }
329  } else if(len != 0)
330  throwError("read failed because string is too big");
331  return str;
332 }
333 
335 {
336  uint8 byte = getU8();
337  if(byte != BINARYTREE_NODE_START)
338  stdext::throw_exception(stdext::format("failed to read node start (getBinaryTree): %d", byte));
339 
340  return BinaryTreePtr(new BinaryTree(asFileStream()));
341 }
342 
344 {
346  addU8(n);
347 }
348 
350 {
352 }
353 
355 {
356  if(!m_caching) {
357  if(PHYSFS_writeBytes(m_fileHandle, &v, 1) != 1)
358  throwError("write failed", true);
359  } else {
360  m_data.add(v);
361  m_pos++;
362  }
363 }
364 
366 {
367  if(!m_caching) {
368  if(PHYSFS_writeULE16(m_fileHandle, v) == 0)
369  throwError("write failed", true);
370  } else {
371  m_data.grow(m_pos + 2);
372  stdext::writeULE16(&m_data[m_pos], v);
373  m_pos += 2;
374  }
375 }
376 
378 {
379  if(!m_caching) {
380  if(PHYSFS_writeULE32(m_fileHandle, v) == 0)
381  throwError("write failed", true);
382  } else {
383  m_data.grow(m_pos + 4);
384  stdext::writeULE32(&m_data[m_pos], v);
385  m_pos += 4;
386  }
387 }
388 
390 {
391  if(!m_caching) {
392  if(PHYSFS_writeULE64(m_fileHandle, v) == 0)
393  throwError("write failed", true);
394  } else {
395  m_data.grow(m_pos + 8);
396  stdext::writeULE64(&m_data[m_pos], v);
397  m_pos += 8;
398  }
399 }
400 
402 {
403  if(!m_caching) {
404  if(PHYSFS_writeBytes(m_fileHandle, &v, 1) != 1)
405  throwError("write failed", true);
406  } else {
407  m_data.add(v);
408  m_pos++;
409  }
410 }
411 
413 {
414  if(!m_caching) {
415  if(PHYSFS_writeSLE16(m_fileHandle, v) == 0)
416  throwError("write failed", true);
417  } else {
418  m_data.grow(m_pos + 2);
419  stdext::writeSLE16(&m_data[m_pos], v);
420  m_pos += 2;
421  }
422 }
423 
425 {
426  if(!m_caching) {
427  if(PHYSFS_writeSLE32(m_fileHandle, v) == 0)
428  throwError("write failed", true);
429  } else {
430  m_data.grow(m_pos + 4);
431  stdext::writeSLE32(&m_data[m_pos], v);
432  m_pos += 4;
433  }
434 }
435 
437 {
438  if(!m_caching) {
439  if(PHYSFS_writeSLE64(m_fileHandle, v) == 0)
440  throwError("write failed", true);
441  } else {
442  m_data.grow(m_pos + 8);
443  stdext::writeSLE64(&m_data[m_pos], v);
444  m_pos += 8;
445  }
446 }
447 
448 void FileStream::addString(const std::string& v)
449 {
450  addU16(v.length());
451  write(v.c_str(), v.length());
452 }
453 
454 void FileStream::throwError(const std::string& message, bool physfsError)
455 {
456  std::string completeMessage = stdext::format("in file '%s': %s", m_name, message);
457  if(physfsError)
458  completeMessage += std::string(": ") + PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
459  stdext::throw_exception(completeMessage);
460 }
461 
DataBuffer::clear
void clear()
Definition: databuffer.h:39
binarytree.h
FileStream::write
void write(const void *buffer, uint count)
Definition: filestream.cpp:130
FileStream::seek
void seek(uint pos)
Definition: filestream.cpp:142
stdext::readULE16
uint16_t readULE16(const uchar *addr)
Definition: math.h:34
FileStream::FileStream
FileStream(const std::string &name, PHYSFS_File *fileHandle, bool writeable)
Definition: filestream.cpp:29
FileStream::add16
void add16(int16 v)
Definition: filestream.cpp:412
BinaryTreePtr
stdext::shared_object_ptr< BinaryTree > BinaryTreePtr
Definition: declarations.h:44
FileStream::close
void close()
Definition: filestream.cpp:78
FileStream::addU32
void addU32(uint32 v)
Definition: filestream.cpp:377
uint32
uint32_t uint32
Definition: types.h:35
FileStream::endNode
void endNode()
Definition: filestream.cpp:349
DataBuffer::size
uint size() const
Definition: databuffer.h:47
stdext::writeULE64
void writeULE64(uchar *addr, uint64_t value)
Definition: math.h:40
int64
int64_t int64
Definition: types.h:38
DataBuffer::add
void add(const T &v)
Definition: databuffer.h:88
FileStream::getString
std::string getString()
Definition: filestream.cpp:309
stdext::format
std::string format()
Definition: format.h:82
stdext::writeULE16
void writeULE16(uchar *addr, uint16_t value)
Definition: math.h:38
int8
int8_t int8
Definition: types.h:41
FileStream::addString
void addString(const std::string &v)
Definition: filestream.cpp:448
uint16
uint16_t uint16
Definition: types.h:36
DataBuffer::resize
void resize(uint n, T def=T())
Definition: databuffer.h:68
FileStream::addU64
void addU64(uint64 v)
Definition: filestream.cpp:389
BinaryTree
Definition: binarytree.h:35
stdext::readSLE32
int32_t readSLE32(const uchar *addr)
Definition: math.h:43
uint
unsigned int uint
Definition: types.h:31
FileStream::cache
void cache()
Definition: filestream.cpp:58
FileStream::getU16
uint16 getU16()
Definition: filestream.cpp:199
FileStream::getBinaryTree
BinaryTreePtr getBinaryTree()
Definition: filestream.cpp:334
stdext::writeULE32
void writeULE32(uchar *addr, uint32_t value)
Definition: math.h:39
int32
int32_t int32
Definition: types.h:39
stdext::writeSLE32
void writeSLE32(uchar *addr, int32_t value)
Definition: math.h:47
FileStream::eof
bool eof()
Definition: filestream.cpp:175
stdext::writeSLE16
void writeSLE16(uchar *addr, int16_t value)
Definition: math.h:46
BINARYTREE_NODE_END
@ BINARYTREE_NODE_END
Definition: binarytree.h:32
FileStream::read
int read(void *buffer, uint size, uint nmemb=1)
Definition: filestream.cpp:109
DataBuffer::data
T * data() const
Definition: databuffer.h:48
FileStream::get8
int8 get8()
Definition: filestream.cpp:246
FileStream::get64
int64 get64()
Definition: filestream.cpp:294
FileStream::add8
void add8(int8 v)
Definition: filestream.cpp:401
g_app
ConsoleApplication g_app
Definition: consoleapplication.cpp:32
uint64
uint64_t uint64
Definition: types.h:34
stdext::throw_exception
void throw_exception(const std::string &what)
Throws a generic exception.
Definition: exception.h:43
stdext::readULE64
uint64_t readULE64(const uchar *addr)
Definition: math.h:36
FileStream::add32
void add32(int32 v)
Definition: filestream.cpp:424
stdext::writeSLE64
void writeSLE64(uchar *addr, int64_t value)
Definition: math.h:48
filestream.h
FileStream::get32
int32 get32()
Definition: filestream.cpp:278
FileStream::getU64
uint64 getU64()
Definition: filestream.cpp:231
FileStream::tell
uint tell()
Definition: filestream.cpp:167
FileStream::skip
void skip(uint len)
Definition: filestream.cpp:154
stdext::readSLE64
int64_t readSLE64(const uchar *addr)
Definition: math.h:44
BINARYTREE_NODE_START
@ BINARYTREE_NODE_START
Definition: binarytree.h:31
stdext::shared_object_ptr
Definition: shared_object.h:39
FileStream::startNode
void startNode(uint8 n)
Definition: filestream.cpp:343
Application::isTerminated
bool isTerminated()
Definition: application.h:50
FileStream::getU32
uint32 getU32()
Definition: filestream.cpp:215
FileStream::flush
void flush()
Definition: filestream.cpp:90
FileStream::get16
int16 get16()
Definition: filestream.cpp:262
FileStream::~FileStream
~FileStream()
Definition: filestream.cpp:49
FileStream::size
uint size()
Definition: filestream.cpp:159
DataBuffer::grow
void grow(uint n)
Definition: databuffer.h:77
FileStream::addU8
void addU8(uint8 v)
Definition: filestream.cpp:354
FileStream::add64
void add64(int64 v)
Definition: filestream.cpp:436
int16
int16_t int16
Definition: types.h:40
FileStream::asFileStream
FileStreamPtr asFileStream()
Definition: filestream.h:78
stdext::readULE32
uint32_t readULE32(const uchar *addr)
Definition: math.h:35
FileStream::getU8
uint8 getU8()
Definition: filestream.cpp:183
uint8
uint8_t uint8
Definition: types.h:37
stdext::readSLE16
int16_t readSLE16(const uchar *addr)
Definition: math.h:42
application.h
FileStream::addU16
void addU16(uint16 v)
Definition: filestream.cpp:365