GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/fs/virtfs/fsdirrwops.cpp Lines: 41 68 60.3 %
Date: 2021-03-17 Branches: 19 38 50.0 %

Line Branch Exec Source
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
5006
    RWOPSINT rwops_seek(SDL_RWops *const rw,
42
                        const RWOPSINT offset,
43
                        const int whence)
44
    {
45
5006
        if (rw == nullptr)
46
            return -1;
47
        File *const handle = static_cast<File *>(
48
5006
            rw->hidden.unknown.data1);
49
5006
        FILEHTYPE fd = handle->mFd;
50
5006
        RWOPSINT pos = 0;
51
52
5006
        if (whence == SEEK_SET)
53
        {
54
            pos = offset;
55
        }
56
3368
        else if (whence == SEEK_CUR)
57
        {
58
#ifdef USE_FILE_FOPEN
59
3357
            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
3357
            if (current == -1)
65
            {
66
                logger->assertLog(
67
                    "VirtFs::rwops_seek: Can't find position in file.");
68
                return -1;
69
            }
70
71
3357
            pos = CAST_S32(current);
72
3357
            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
3357
            if (offset == 0)  /* this is a "tell" call. We're done. */
80
                return pos;
81
82
25
            pos += offset;
83
        }
84
11
        else if (whence == SEEK_END)
85
        {
86
11
            int64_t len = 0;
87
#ifdef USE_FILE_FOPEN
88
11
            const long curpos = ftell(fd);
89
11
            if (curpos < 0)
90
            {
91
                reportAlways("FsDir::fileLength ftell error.")
92
                return -1;
93
            }
94
11
            fseek(fd, 0, SEEK_END);
95
11
            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
11
            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
11
            pos = static_cast<RWOPSINT>(len);
124
11
            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
11
            pos += offset;
135
        }
136
        else
137
        {
138
            logger->assertLog(
139
                "VirtFs::rwops_seek: Invalid 'whence' parameter.");
140
            return -1;
141
        }
142
143
1674
        if (pos < 0)
144
        {
145
1
            logger->assertLog("VirtFs::rwops_seek: "
146
1
                "Attempt to seek past start of file.");
147
1
            return -1;
148
        }
149
150
1673
        const int64_t res = FILESEEK(fd, pos, SEEK_SET);
151
1673
        if (res == -1)
152
        {
153
            logger->assertLog("VirtFs::rwops_seek: seek error.");
154
            return -1;
155
        }
156
157
        return pos;
158
    }
159
160
45302
    RWOPSSIZE rwops_read(SDL_RWops *const rw,
161
                         void *const ptr,
162
                         const RWOPSSIZE size,
163
                         const RWOPSSIZE maxnum)
164
    {
165
45302
        if (rw == nullptr)
166
            return 0;
167
        File *const handle = static_cast<File *>(
168
45302
            rw->hidden.unknown.data1);
169
45302
        FILEHTYPE fd = handle->mFd;
170
171
#ifdef USE_FILE_FOPEN
172
90604
        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
45302
        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
1621
    int rwops_close(SDL_RWops *const rw)
234
    {
235
1621
        if (rw == nullptr)
236
            return 0;
237
        File *const handle = static_cast<File*>(
238
1621
            rw->hidden.unknown.data1);
239
1621
        delete handle;
240
1621
        SDL_FreeRW(rw);
241
1621
        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