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/physfs_sdl.hpp" |
18 | |
19 | #include <physfs.h> |
20 | #include <sstream> |
21 | #include <stdexcept> |
22 | #include <assert.h> |
23 | #include <stdio.h> |
24 | |
25 | #include "util/log.hpp" |
26 | |
27 | namespace { |
28 | |
29 | Sint64 funcSize(struct SDL_RWops* context) |
30 | { |
31 | PHYSFS_file* file = static_cast<PHYSFS_file*>(context->hidden.unknown.data1); |
32 | return PHYSFS_fileLength(file); |
33 | } |
34 | |
35 | Sint64 funcSeek(struct SDL_RWops* context, Sint64 offset, int whence) |
36 | { |
37 | PHYSFS_file* file = static_cast<PHYSFS_file*>(context->hidden.unknown.data1); |
38 | int res; |
39 | switch (whence) { |
40 | case SEEK_SET: |
41 | res = PHYSFS_seek(file, offset); |
42 | break; |
43 | case SEEK_CUR: |
44 | res = PHYSFS_seek(file, PHYSFS_tell(file) + offset); |
45 | break; |
46 | case SEEK_END: |
47 | res = PHYSFS_seek(file, PHYSFS_fileLength(file) + offset); |
48 | break; |
49 | default: |
50 | res = 0; // NOLINT |
51 | assert(false); |
52 | break; |
53 | } |
54 | if (res == 0) { |
55 | log_warning << "Error seeking in file: " << PHYSFS_getLastErrorCode() << std::endl; |
56 | return -1; |
57 | } |
58 | |
59 | return static_cast<int>(PHYSFS_tell(file)); |
60 | } |
61 | |
62 | size_t funcRead(struct SDL_RWops* context, void* ptr, size_t size, size_t maxnum) |
63 | { |
64 | PHYSFS_file* file = static_cast<PHYSFS_file*>(context->hidden.unknown.data1); |
65 | |
66 | PHYSFS_sint64 res = PHYSFS_readBytes(file, ptr, size * maxnum); |
67 | if (res < 0) |
68 | { |
69 | return 0; |
70 | } |
71 | else |
72 | { |
73 | return static_cast<size_t>(res / size); |
74 | } |
75 | } |
76 | |
77 | size_t funcWrite(struct SDL_RWops* context, const void* ptr, size_t size, size_t num) |
78 | { |
79 | PHYSFS_file* file = static_cast<PHYSFS_file*>(context->hidden.unknown.data1); |
80 | |
81 | PHYSFS_sint64 res = PHYSFS_writeBytes(file, ptr, size * num); |
82 | if (res < 0) |
83 | { |
84 | return 0; |
85 | } |
86 | else |
87 | { |
88 | return static_cast<size_t>(res / size); |
89 | } |
90 | } |
91 | |
92 | int funcClose(struct SDL_RWops* context) |
93 | { |
94 | PHYSFS_file* file = static_cast<PHYSFS_file*>(context->hidden.unknown.data1); |
95 | |
96 | PHYSFS_close(file); |
97 | delete context; |
98 | |
99 | return 0; |
100 | } |
101 | |
102 | } // namespace |
103 | |
104 | SDL_RWops* get_physfs_SDLRWops(const std::string& filename) |
105 | { |
106 | // check this as PHYSFS seems to be buggy and still returns a |
107 | // valid pointer in this case |
108 | if (filename.empty()) { |
109 | throw std::runtime_error("Couldn't open file: empty filename" ); |
110 | } |
111 | |
112 | PHYSFS_file* file = static_cast<PHYSFS_file*>(PHYSFS_openRead(filename.c_str())); |
113 | if (!file) { |
114 | std::stringstream msg; |
115 | msg << "Couldn't open '" << filename << "': " |
116 | << PHYSFS_getLastErrorCode(); |
117 | throw std::runtime_error(msg.str()); |
118 | } |
119 | |
120 | SDL_RWops* ops = new SDL_RWops; |
121 | ops->size = funcSize; |
122 | ops->seek = funcSeek; |
123 | ops->read = funcRead; |
124 | ops->write = funcWrite; |
125 | ops->close = funcClose; |
126 | ops->type = SDL_RWOPS_UNKNOWN; |
127 | ops->hidden.unknown.data1 = file; |
128 | |
129 | return ops; |
130 | } |
131 | |
132 | SDL_RWops* get_writable_physfs_SDLRWops(const std::string& filename) |
133 | { |
134 | // check this as PHYSFS seems to be buggy and still returns a |
135 | // valid pointer in this case |
136 | if (filename.empty()) { |
137 | throw std::runtime_error("Couldn't open file: empty filename" ); |
138 | } |
139 | |
140 | PHYSFS_file* file = static_cast<PHYSFS_file*>(PHYSFS_openWrite(filename.c_str())); |
141 | if (!file) { |
142 | std::stringstream msg; |
143 | msg << "Couldn't open '" << filename << "' for writing: " |
144 | << PHYSFS_getLastErrorCode(); |
145 | throw std::runtime_error(msg.str()); |
146 | } |
147 | |
148 | SDL_RWops* ops = new SDL_RWops; |
149 | ops->size = funcSize; |
150 | ops->seek = funcSeek; |
151 | ops->read = funcRead; |
152 | ops->write = funcWrite; |
153 | ops->close = funcClose; |
154 | ops->type = SDL_RWOPS_UNKNOWN; |
155 | ops->hidden.unknown.data1 = file; |
156 | |
157 | return ops; |
158 | } |
159 | |
160 | /* EOF */ |
161 | |