ManaPlus
fsdirrwops.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2013-2019 The ManaPlus Developers
4  * Copyright (C) 2019-2021 Andrei Karas
5  *
6  * This file is part of The ManaPlus Client.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "fs/virtfs/fsdirrwops.h"
23 
24 #include "fs/virtfs/file.h"
25 
26 #include "utils/cast.h"
27 #include "utils/checkutils.h"
28 
29 PRAGMA48(GCC diagnostic push)
30 PRAGMA48(GCC diagnostic ignored "-Wshadow")
31 #include <SDL_rwops.h>
32 PRAGMA48(GCC diagnostic pop)
33 
34 #include "debug.h"
35 
36 namespace VirtFs
37 {
38 
39 namespace FsDir
40 {
41  RWOPSINT rwops_seek(SDL_RWops *const rw,
42  const RWOPSINT offset,
43  const int whence)
44  {
45  if (rw == nullptr)
46  return -1;
47  File *const handle = static_cast<File *>(
48  rw->hidden.unknown.data1);
49  FILEHTYPE fd = handle->mFd;
50  RWOPSINT pos = 0;
51 
52  if (whence == SEEK_SET)
53  {
54  pos = offset;
55  }
56  else if (whence == SEEK_CUR)
57  {
58 #ifdef USE_FILE_FOPEN
59  const int64_t current = ftell(fd);
60 #else // USE_FILE_FOPEN
61  const int64_t current = lseek(fd, 0, SEEK_CUR);
62 #endif // USE_FILE_FOPEN
63 
64  if (current == -1)
65  {
67  "VirtFs::rwops_seek: Can't find position in file.");
68  return -1;
69  }
70 
71  pos = CAST_S32(current);
72  if (static_cast<int64_t>(pos) != current)
73  {
74  logger->assertLog("VirtFs::rwops_seek: "
75  "Can't fit current file position in an int!");
76  return -1;
77  }
78 
79  if (offset == 0) /* this is a "tell" call. We're done. */
80  return pos;
81 
82  pos += offset;
83  }
84  else if (whence == SEEK_END)
85  {
86  int64_t len = 0;
87 #ifdef USE_FILE_FOPEN
88  const long curpos = ftell(fd);
89  if (curpos < 0)
90  {
91  reportAlways("FsDir::fileLength ftell error.")
92  return -1;
93  }
94  fseek(fd, 0, SEEK_END);
95  len = ftell(fd);
96 // fseek(fd, curpos, SEEK_SET);
97 #else // USE_FILE_FOPEN
98  struct stat statbuf;
99  if (fstat(fd, &statbuf) == -1)
100  {
101  reportAlways("FsDir::fileLength error.")
102  len = -1;
103  }
104  else
105  {
106  len = static_cast<int64_t>(statbuf.st_size);
107  }
108 #endif // USE_FILE_FOPEN
109 
110  if (len == -1)
111  {
112 #ifdef USE_FILE_FOPEN
113  if (fseek(fd, curpos, SEEK_SET) < 0)
114  {
115  reportAlways("FsDir::fileLength fseek error.")
116  }
117 #endif // USE_FILE_FOPEN
118  logger->assertLog(
119  "VirtFs::rwops_seek:Can't find end of file.");
120  return -1;
121  }
122 
123  pos = static_cast<RWOPSINT>(len);
124  if (static_cast<int64_t>(pos) != len)
125  {
126 #ifdef USE_FILE_FOPEN
127  fseek(fd, curpos, SEEK_SET);
128 #endif // USE_FILE_FOPEN
129  logger->assertLog("VirtFs::rwops_seek: "
130  "Can't fit end-of-file position in an int!");
131  return -1;
132  }
133 
134  pos += offset;
135  }
136  else
137  {
138  logger->assertLog(
139  "VirtFs::rwops_seek: Invalid 'whence' parameter.");
140  return -1;
141  }
142 
143  if (pos < 0)
144  {
145  logger->assertLog("VirtFs::rwops_seek: "
146  "Attempt to seek past start of file.");
147  return -1;
148  }
149 
150  const int64_t res = FILESEEK(fd, pos, SEEK_SET);
151  if (res == -1)
152  {
153  logger->assertLog("VirtFs::rwops_seek: seek error.");
154  return -1;
155  }
156 
157  return pos;
158  }
159 
160  RWOPSSIZE rwops_read(SDL_RWops *const rw,
161  void *const ptr,
162  const RWOPSSIZE size,
163  const RWOPSSIZE maxnum)
164  {
165  if (rw == nullptr)
166  return 0;
167  File *const handle = static_cast<File *>(
168  rw->hidden.unknown.data1);
169  FILEHTYPE fd = handle->mFd;
170 
171 #ifdef USE_FILE_FOPEN
172  const int64_t rc = fread(ptr, size, maxnum, fd);
173 #else // USE_FILE_FOPEN
174  int max = size * maxnum;
175  int cnt = ::read(fd, ptr, max);
176  if (cnt <= 0)
177  return cnt;
178  const int64_t rc = cnt / size;
179 #endif // USE_FILE_FOPEN
180 
181 #ifndef USE_FILE_FOPEN
182  if (rc != static_cast<int64_t>(maxnum))
183  {
184  const int64_t pos = lseek(fd, 0, SEEK_CUR);
185  struct stat statbuf;
186  if (fstat(fd, &statbuf) == -1)
187  {
188  reportAlways("FsDir::fileLength error.")
189  return CAST_S32(rc);
190  }
191  }
192 #endif // USE_FILE_FOPEN
193  return CAST_S32(rc);
194  }
195 
196  RWOPSSIZE rwops_write(SDL_RWops *const rw,
197  const void *const ptr,
198  const RWOPSSIZE size,
199  const RWOPSSIZE maxnum)
200  {
201  if (rw == nullptr)
202  return 0;
203  File *const handle = static_cast<File *>(
204  rw->hidden.unknown.data1);
205  FILEHTYPE fd = handle->mFd;
206 
207 #ifdef USE_FILE_FOPEN
208  const int64_t rc = fwrite(ptr, size, maxnum, fd);
209 #else // USE_FILE_FOPEN
210  int max = size * maxnum;
211  int cnt = ::write(fd, ptr, max);
212  if (cnt <= 0)
213  return cnt;
214  const int64_t rc = cnt / size;
215 #endif // USE_FILE_FOPEN
216 
217 #ifndef USE_FILE_FOPEN
218  if (rc != static_cast<int64_t>(maxnum))
219  {
220  const int64_t pos = lseek(fd, 0, SEEK_CUR);
221  struct stat statbuf;
222  if (fstat(fd, &statbuf) == -1)
223  {
224  reportAlways("FsDir::fileLength error.")
225  return CAST_S32(rc);
226  }
227  }
228 #endif // USE_FILE_FOPEN
229 
230  return CAST_S32(rc);
231  }
232 
233  int rwops_close(SDL_RWops *const rw)
234  {
235  if (rw == nullptr)
236  return 0;
237  File *const handle = static_cast<File*>(
238  rw->hidden.unknown.data1);
239  delete handle;
240  SDL_FreeRW(rw);
241  return 0;
242  }
243 
244 #ifdef USE_SDL2
245  RWOPSINT rwops_size(SDL_RWops *const rw)
246  {
247  File *const handle = static_cast<File *>(
248  rw->hidden.unknown.data1);
249  FILEHTYPE fd = handle->mFd;
250 #ifdef USE_FILE_FOPEN
251  const long pos = ftell(fd);
252  fseek(fd, 0, SEEK_END);
253  const long sz = ftell(fd);
254  fseek(fd, pos, SEEK_SET);
255  return sz;
256 #else // USE_FILE_FOPEN
257  struct stat statbuf;
258  if (fstat(fd, &statbuf) == -1)
259  {
260  reportAlways("FsDir::fileLength error.")
261  return -1;
262  }
263  return static_cast<int64_t>(statbuf.st_size);
264 #endif // USE_FILE_FOPEN
265  }
266 #endif // USE_SDL2
267 
268 } // namespace FsDir
269 
270 } // namespace VirtFs
#define CAST_S32
Definition: cast.h:30
#define reportAlways(...)
Definition: checkutils.h:253
void assertLog(const char *const log_text,...)
Definition: logger.cpp:316
#define FILEHTYPE
Definition: fileapi.h:28
#define FILESEEK
Definition: fileapi.h:33
#define PRAGMA48(str)
Definition: localconsts.h:199
Logger * logger
Definition: logger.cpp:89
int size()
Definition: emotedb.cpp:306
int rwops_write(SDL_RWops *const rw, const void *const ptr, const int size, const int maxnum)
Definition: fsdirrwops.cpp:196
int32_t rwops_seek(SDL_RWops *const rw, const int32_t offset, const int whence)
Definition: fsdirrwops.cpp:41
int rwops_close(SDL_RWops *const rw)
Definition: fsdirrwops.cpp:233
int64_t read(File *const file, void *const buffer, const uint32_t objSize, const uint32_t objCount)
Definition: fsdir.cpp:320
int rwops_read(SDL_RWops *const rw, void *const ptr, const int size, const int maxnum)
Definition: fsdirrwops.cpp:160
int64_t write(File *const file, const void *const buffer, const uint32_t objSize, const uint32_t objCount)
Definition: fsdir.cpp:344
#define RWOPSSIZE
Definition: rwopstypes.h:32
#define RWOPSINT
Definition: rwopstypes.h:31
FILE *const mFd
Definition: file.h:57