1 | // SuperTux |
2 | // Copyright (C) 2006 Matthias Braun <matze@braunis.de> |
3 | // |
4 | // This program is free software: you can redistribute it and/or modify |
5 | // it under the terms of the GNU General Public License as published by |
6 | // the Free Software Foundation, either version 3 of the License, or |
7 | // (at your option) any later version. |
8 | // |
9 | // This program is distributed in the hope that it will be useful, |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | // GNU General Public License for more details. |
13 | // |
14 | // You should have received a copy of the GNU General Public License |
15 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | |
17 | #include "physfs/ifile_streambuf.hpp" |
18 | |
19 | #include <assert.h> |
20 | #include <physfs.h> |
21 | #include <sstream> |
22 | #include <stdexcept> |
23 | |
24 | IFileStreambuf::IFileStreambuf(const std::string& filename) : |
25 | file(), |
26 | buf() |
27 | { |
28 | // check this as PHYSFS seems to be buggy and still returns a |
29 | // valid pointer in this case |
30 | if (filename.empty()) { |
31 | throw std::runtime_error("Couldn't open file: empty filename" ); |
32 | } |
33 | file = PHYSFS_openRead(filename.c_str()); |
34 | if (file == nullptr) { |
35 | std::stringstream msg; |
36 | msg << "Couldn't open file '" << filename << "': " |
37 | << PHYSFS_getLastErrorCode(); |
38 | throw std::runtime_error(msg.str()); |
39 | } |
40 | } |
41 | |
42 | IFileStreambuf::~IFileStreambuf() |
43 | { |
44 | PHYSFS_close(file); |
45 | } |
46 | |
47 | int |
48 | IFileStreambuf::underflow() |
49 | { |
50 | if (PHYSFS_eof(file)) { |
51 | return traits_type::eof(); |
52 | } |
53 | |
54 | PHYSFS_sint64 bytesread = PHYSFS_readBytes(file, buf, sizeof(buf)); |
55 | if (bytesread <= 0) { |
56 | return traits_type::eof(); |
57 | } |
58 | setg(buf, buf, buf + bytesread); |
59 | |
60 | return buf[0]; |
61 | } |
62 | |
63 | IFileStreambuf::pos_type |
64 | IFileStreambuf::seekpos(pos_type pos, std::ios_base::openmode) |
65 | { |
66 | if (PHYSFS_seek(file, static_cast<PHYSFS_uint64> (pos)) == 0) { |
67 | return pos_type(off_type(-1)); |
68 | } |
69 | |
70 | // the seek invalidated the buffer |
71 | setg(buf, buf, buf); |
72 | return pos; |
73 | } |
74 | |
75 | IFileStreambuf::pos_type |
76 | IFileStreambuf::seekoff(off_type off, std::ios_base::seekdir dir, |
77 | std::ios_base::openmode mode) |
78 | { |
79 | off_type pos = off; |
80 | PHYSFS_sint64 ptell = PHYSFS_tell(file); |
81 | |
82 | switch (dir) { |
83 | case std::ios_base::beg: |
84 | break; |
85 | case std::ios_base::cur: |
86 | if (off == 0) |
87 | return static_cast<pos_type> (ptell) - static_cast<pos_type> (egptr() - gptr()); |
88 | pos += static_cast<off_type> (ptell) - static_cast<off_type> (egptr() - gptr()); |
89 | break; |
90 | case std::ios_base::end: |
91 | pos += static_cast<off_type> (PHYSFS_fileLength(file)); |
92 | break; |
93 | default: |
94 | assert(false); |
95 | return pos_type(off_type(-1)); |
96 | } |
97 | |
98 | return seekpos(static_cast<pos_type> (pos), mode); |
99 | } |
100 | |
101 | /* EOF */ |
102 | |