GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/fs/virtfs/fsdirrwops.cpp Lines: 47 66 71.2 %
Date: 2017-11-29 Branches: 18 36 50.0 %

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