GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/fs/files.cpp Lines: 35 66 53.0 %
Date: 2017-11-29 Branches: 17 78 21.8 %

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/files.h"
22
23
#include "fs/mkdir.h"
24
#if defined(ANDROID) || defined(__native_client__)
25
#include "fs/paths.h"
26
27
#include "fs/virtfs/fs.h"
28
#include "fs/virtfs/tools.h"
29
#include "fs/virtfs/list.h"
30
#endif  // defined(ANDROID) || defined(__native_client__)
31
32
#if defined(ANDROID) || defined(__native_client__)
33
#include "utils/foreach.h"
34
#endif  // defined(ANDROID) || defined(__native_client__)
35
36
#include "utils/checkutils.h"
37
#include "utils/stringutils.h"
38
39
#include <dirent.h>
40
#include <sys/stat.h>
41
42
#include "debug.h"
43
44
extern const char *dirSeparator;
45
46
#ifdef ANDROID
47
void Files::extractLocale()
48
{
49
    // in future need also remove all locales in local dir
50
51
    const std::string fileName2 = pathJoin(getenv("APPDIR"), "locale.zip");
52
    VirtFs::mountZip(fileName2, Append_false);
53
54
    const std::string localDir = std::string(getenv("APPDIR"));
55
    VirtFs::List *const rootDirs = VirtFs::enumerateFiles("locale");
56
    FOR_EACH (StringVectCIter, i, rootDirs->names)
57
    {
58
        const std::string dir = pathJoin("locale", *i);
59
        if (VirtFs::isDirectory(dir))
60
        {
61
            const std::string moFile = dir + "/LC_MESSAGES/manaplus.mo";
62
            if (VirtFs::exists((moFile)))
63
            {
64
                const std::string localFile = pathJoin(localDir, moFile);
65
                const std::string localDir2 = pathJoin(localDir,
66
                    dir,
67
                    "LC_MESSAGES");
68
                mkdir_r(localDir2.c_str());
69
                copyVirtFsFile(moFile, localFile);
70
            }
71
        }
72
    }
73
    VirtFs::freeList(rootDirs);
74
    VirtFs::unmountZip(fileName2);
75
    remove(fileName2.c_str());
76
}
77
#endif  // ANDROID
78
79
#if defined(ANDROID) || defined(__native_client__)
80
81
namespace
82
{
83
#ifdef ANDROID
84
    int mFilesCount = 0;
85
#endif  // ANDROID
86
87
    Files::CopyFileCallbackPtr mCallbackPtr = nullptr;
88
}  // namespace
89
90
void Files::setCopyCallBack(Files::CopyFileCallbackPtr callback)
91
{
92
    mCallbackPtr = callback;
93
}
94
95
void Files::copyVirtFsFile(const std::string &restrict inFile,
96
                           const std::string &restrict outFile)
97
{
98
    int size = 0;
99
    const char *const buf = VirtFs::loadFile(inFile, size);
100
    FILE *const file = fopen(outFile.c_str(), "w");
101
    fwrite(buf, 1, size, file);
102
    fclose(file);
103
    delete [] buf;
104
#ifdef ANDROID
105
    if (mCallbackPtr)
106
    {
107
        mCallbackPtr(mFilesCount);
108
        mFilesCount ++;
109
    }
110
#endif  // ANDROID
111
}
112
113
void Files::copyVirtFsDir(const std::string &restrict inDir,
114
                          const std::string &restrict outDir)
115
{
116
    mkdir_r(outDir.c_str());
117
    VirtFs::List *const files = VirtFs::enumerateFiles(inDir);
118
    FOR_EACH (StringVectCIter, i, files->names)
119
    {
120
        const std::string file = pathJoin(inDir, *i);
121
        const std::string outDir2 = pathJoin(outDir, *i);
122
        if (VirtFs::isDirectory(file))
123
            copyVirtFsDir(file, outDir2);
124
        else
125
            copyVirtFsFile(file, outDir2);
126
    }
127
    VirtFs::freeList(files);
128
}
129
130
#endif  // ANDROID __native_client__
131
132
2
int Files::renameFile(const std::string &restrict srcName,
133
                      const std::string &restrict dstName)
134
{
135
#if defined __native_client__
136
    FILE *srcFile = fopen(srcName.c_str(), "rb");
137
    if (srcFile == nullptr)
138
        return -1;
139
    FILE *dstFile = fopen(dstName.c_str(), "w+b");
140
    if (dstFile == nullptr)
141
    {
142
        fclose(srcFile);
143
        return -1;
144
    }
145
146
    const int chunkSize = 500000;
147
    char *buf = new char[chunkSize];
148
    size_t sz = 0;
149
    while ((sz = fread(buf, 1, chunkSize, srcFile)))
150
    {
151
        if (fwrite(buf, 1, sz, dstFile) != sz)
152
        {
153
            delete [] buf;
154
            fclose(srcFile);
155
            fclose(dstFile);
156
            ::remove(dstName.c_str());
157
            return -1;
158
        }
159
    }
160
161
    delete [] buf;
162
    fclose(srcFile);
163
    fclose(dstFile);
164
    if (!::remove(srcName.c_str()))
165
        return 0;
166
167
    return -1;
168
#else  // defined __native_client__
169
170
4
    return ::rename(srcName.c_str(), dstName.c_str());
171
#endif  // defined __native_client__
172
}
173
174
6
int Files::copyFile(const std::string &restrict srcName,
175
                    const std::string &restrict dstName)
176
{
177
6
    FILE *srcFile = fopen(srcName.c_str(), "rb");
178
6
    if (srcFile == nullptr)
179
        return -1;
180
4
    FILE *dstFile = fopen(dstName.c_str(), "w+b");
181
4
    if (dstFile == nullptr)
182
    {
183
2
        fclose(srcFile);
184
2
        return -1;
185
    }
186
187
2
    const int chunkSize = 512000;
188
2
    char *buf = new char[chunkSize];
189
2
    size_t sz = 0;
190
4
    while ((sz = fread(buf, 1, chunkSize, srcFile)) != 0u)
191
    {
192
2
        if (fwrite(buf, 1, sz, dstFile) != sz)
193
        {
194
            delete [] buf;
195
            fclose(srcFile);
196
            fclose(dstFile);
197
            return -1;
198
        }
199
    }
200
201
2
    delete [] buf;
202
2
    fclose(srcFile);
203
2
    fclose(dstFile);
204
2
    return 0;
205
}
206
207
34057
bool Files::existsLocal(const std::string &path)
208
{
209
    struct stat statbuf;
210
#ifdef WIN32
211
    // in windows path\file.ext\ by default detected as exists
212
    // if file.ext is not directory, need return false
213
    const bool res = (stat(path.c_str(), &statbuf) == 0);
214
    if (res == false)
215
        return false;
216
    if ((findLast(path, "/") == true || findLast(path, "\\") == true) &&
217
        S_ISDIR(statbuf.st_mode) == 0)
218
    {
219
        return false;
220
    }
221
    return true;
222
#else  // WIN32
223
68114
    return stat(path.c_str(), &statbuf) == 0;
224
#endif  // WIN32
225
}
226
227
2
bool Files::loadTextFileLocal(const std::string &fileName,
228
                              StringVect &lines)
229
{
230
4
    std::ifstream file;
231
    char line[501];
232
233
2
    file.open(fileName.c_str(), std::ios::in);
234
235
2
    if (!file.is_open())
236
    {
237
        reportAlways("Couldn't load text file: %s",
238
            fileName.c_str());
239
        return false;
240
    }
241
242

16
    while (file.getline(line, 500))
243
20
        lines.push_back(line);
244
245
    return true;
246
}
247
248
4
void Files::saveTextFile(const std::string &path,
249
                         const std::string &restrict name,
250
                         const std::string &restrict text)
251
{
252
4
    if (mkdir_r(path.c_str()) == 0)
253
    {
254
8
        std::ofstream file;
255
8
        std::string fileName = pathJoin(path, name);
256
4
        file.open(fileName.c_str(), std::ios::out);
257
4
        if (file.is_open())
258
        {
259
8
            file << text << std::endl;
260
        }
261
        else
262
        {
263
            reportAlways("Error opening file for writing: %s",
264
                fileName.c_str());
265
        }
266
4
        file.close();
267
    }
268
4
}
269
270
void Files::deleteFilesInDirectory(std::string path)
271
{
272
    path = pathJoin(path, dirSeparator);
273
    const struct dirent *next_file = nullptr;
274
    DIR *const dir = opendir(path.c_str());
275
276
    if (dir != nullptr)
277
    {
278
        while ((next_file = readdir(dir)) != nullptr)
279
        {
280
            const std::string file = next_file->d_name;
281
            if (file != "." && file != "..")
282
                remove((path + file).c_str());
283
        }
284
        closedir(dir);
285
    }
286
}
287
288
void Files::enumFiles(StringVect &files,
289
                      std::string path,
290
                      const bool skipSymlinks A_WIN_UNUSED)
291
{
292
    if (findLast(path, dirSeparator) == false)
293
        path += dirSeparator;
294
    DIR *const dir = opendir(path.c_str());
295
296
    if (dir != nullptr)
297
    {
298
        const struct dirent *next_file = nullptr;
299
        while ((next_file = readdir(dir)) != nullptr)
300
        {
301
            const std::string file = next_file->d_name;
302
            if (file == "." || file == "..")
303
                continue;
304
#ifndef WIN32
305
            if (skipSymlinks == true)
306
            {
307
                struct stat statbuf;
308
                if (lstat(path.c_str(), &statbuf) == 0 &&
309
                    S_ISLNK(statbuf.st_mode) != 0)
310
                {
311
                    continue;
312
                }
313
            }
314
#endif  // WIN32
315
            files.push_back(file);
316
        }
317
        closedir(dir);
318
    }
319
}