~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to ext/native/file/file_util.cpp

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifdef _WIN32
 
2
#define WIN32_LEAN_AND_MEAN
 
3
#include <Windows.h>
 
4
#include <direct.h>
 
5
#ifndef strcasecmp
 
6
#define strcasecmp _stricmp
 
7
#endif
 
8
#define fseeko _fseeki64
 
9
#define ftello _ftelli64
 
10
#else
 
11
#include <dirent.h>
 
12
#include <unistd.h>
 
13
#include <errno.h>
 
14
#endif
 
15
#include <cstring>
 
16
#include <string>
 
17
#include <set>
 
18
#include <algorithm>
 
19
#include <cstdio>
 
20
#include <sys/stat.h>
 
21
#include <ctype.h>
 
22
 
 
23
#include "base/logging.h"
 
24
#include "base/basictypes.h"
 
25
#include "file/file_util.h"
 
26
#include "util/text/utf8.h"
 
27
 
 
28
#if !defined(__linux__) && !defined(_WIN32) && !defined(__QNX__)
 
29
#define stat64 stat
 
30
#endif
 
31
 
 
32
// Hack
 
33
#ifdef __SYMBIAN32__
 
34
static inline int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
 
35
        struct dirent *readdir_entry;
 
36
 
 
37
        readdir_entry = readdir(dirp);
 
38
        if (readdir_entry == NULL) {
 
39
                *result = NULL;
 
40
                return errno;
 
41
        }
 
42
 
 
43
        *entry = *readdir_entry;
 
44
        *result = entry;
 
45
        return 0;
 
46
}
 
47
#endif
 
48
 
 
49
FILE *openCFile(const std::string &filename, const char *mode)
 
50
{
 
51
#if defined(_WIN32) && defined(UNICODE)
 
52
        return _wfopen(ConvertUTF8ToWString(filename).c_str(), ConvertUTF8ToWString(mode).c_str());
 
53
#else
 
54
        return fopen(filename.c_str(), mode);
 
55
#endif
 
56
}
 
57
 
 
58
bool writeStringToFile(bool text_file, const std::string &str, const char *filename)
 
59
{
 
60
        FILE *f = openCFile(filename, text_file ? "w" : "wb");
 
61
        if (!f)
 
62
                return false;
 
63
        size_t len = str.size();
 
64
        if (len != fwrite(str.data(), 1, str.size(), f))
 
65
        {
 
66
                fclose(f);
 
67
                return false;
 
68
        }
 
69
        fclose(f);
 
70
        return true;
 
71
}
 
72
 
 
73
bool writeDataToFile(bool text_file, const void* data, const unsigned int size, const char *filename)
 
74
{
 
75
        FILE *f = openCFile(filename, text_file ? "w" : "wb");
 
76
        if (!f)
 
77
                return false;
 
78
        size_t len = size;
 
79
        if (len != fwrite(data, 1, len, f))
 
80
        {
 
81
                fclose(f);
 
82
                return false;
 
83
        }
 
84
        fclose(f);
 
85
        return true;
 
86
}
 
87
 
 
88
uint64_t GetSize(FILE *f)
 
89
{
 
90
        // This will only support 64-bit when large file support is available.
 
91
        // That won't be the case on some versions of Android, at least.
 
92
#if defined(ANDROID) || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64)
 
93
        int fd = fileno(f);
 
94
 
 
95
        off64_t pos = lseek64(fd, 0, SEEK_CUR);
 
96
        off64_t size = lseek64(fd, 0, SEEK_END);
 
97
        if (size != pos && lseek64(fd, pos, SEEK_SET) != pos) {
 
98
                // Should error here.
 
99
                return 0;
 
100
        }
 
101
        return size;
 
102
#else
 
103
        uint64_t pos = ftello(f);
 
104
        if (fseek(f, 0, SEEK_END) != 0) {
 
105
                return 0;
 
106
        }
 
107
        uint64_t size = ftello(f);
 
108
        // Reset the seek position to where it was when we started.
 
109
        if (size != pos && fseeko(f, pos, SEEK_SET) != 0) {
 
110
                // Should error here.
 
111
                return 0;
 
112
        }
 
113
        return size;
 
114
#endif
 
115
}
 
116
 
 
117
bool readFileToString(bool text_file, const char *filename, std::string &str)
 
118
{
 
119
        FILE *f = openCFile(filename, text_file ? "r" : "rb");
 
120
        if (!f)
 
121
                return false;
 
122
        size_t len = (size_t)GetSize(f);
 
123
        char *buf = new char[len + 1];
 
124
        buf[fread(buf, 1, len, f)] = 0;
 
125
        str = std::string(buf, len);
 
126
        fclose(f);
 
127
        delete [] buf;
 
128
        return true;
 
129
}
 
130
 
 
131
 
 
132
bool readDataFromFile(bool text_file, unsigned char* &data, const unsigned int size, const char *filename)
 
133
{
 
134
        FILE *f = openCFile(filename, text_file ? "r" : "rb");
 
135
        if (!f)
 
136
                return false;
 
137
        size_t len = (size_t)GetSize(f);
 
138
        if(len < size) {
 
139
                fclose(f);
 
140
                return false;
 
141
        }
 
142
        data[fread(data, 1, size, f)] = 0;
 
143
        fclose(f);
 
144
        return true;
 
145
}
 
146
 
 
147
// Returns true if filename is a directory
 
148
bool isDirectory(const std::string &filename) {
 
149
        FileInfo info;
 
150
        getFileInfo(filename.c_str(), &info);
 
151
        return info.isDirectory;
 
152
}
 
153
 
 
154
bool getFileInfo(const char *path, FileInfo *fileInfo) {
 
155
        // TODO: Expand relative paths?
 
156
        fileInfo->fullName = path;
 
157
 
 
158
#ifdef _WIN32
 
159
        WIN32_FILE_ATTRIBUTE_DATA attrs;
 
160
        if (!GetFileAttributesExW(ConvertUTF8ToWString(path).c_str(), GetFileExInfoStandard, &attrs)) {
 
161
                fileInfo->size = 0;
 
162
                fileInfo->isDirectory = false;
 
163
                fileInfo->exists = false;
 
164
                return false;
 
165
        }
 
166
        fileInfo->size = (uint64_t)attrs.nFileSizeLow | ((uint64_t)attrs.nFileSizeHigh << 32);
 
167
        fileInfo->isDirectory = (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
 
168
        fileInfo->isWritable = (attrs.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
 
169
        fileInfo->exists = true;
 
170
#else
 
171
        struct stat64 file_info;
 
172
 
 
173
        std::string copy(path);
 
174
 
 
175
        int result = stat64(copy.c_str(), &file_info);
 
176
 
 
177
        if (result < 0) {
 
178
                WLOG("IsDirectory: stat failed on %s", path);
 
179
                fileInfo->exists = false;
 
180
                return false;
 
181
        }
 
182
 
 
183
        fileInfo->isDirectory = S_ISDIR(file_info.st_mode);
 
184
        fileInfo->isWritable = false;
 
185
        fileInfo->size = file_info.st_size;
 
186
        fileInfo->exists = true;
 
187
        // HACK: approximation
 
188
        if (file_info.st_mode & 0200)
 
189
                fileInfo->isWritable = true;
 
190
#endif
 
191
        return true;
 
192
}
 
193
 
 
194
std::string getFileExtension(const std::string &fn) {
 
195
        int pos = (int)fn.rfind(".");
 
196
        if (pos < 0) return "";
 
197
        std::string ext = fn.substr(pos+1);
 
198
        for (size_t i = 0; i < ext.size(); i++) {
 
199
                ext[i] = tolower(ext[i]);
 
200
        }
 
201
        return ext;
 
202
}
 
203
 
 
204
bool FileInfo::operator <(const FileInfo &other) const {
 
205
        if (isDirectory && !other.isDirectory)
 
206
                return true;
 
207
        else if (!isDirectory && other.isDirectory)
 
208
                return false;
 
209
        if (strcasecmp(name.c_str(), other.name.c_str()) < 0)
 
210
                return true;
 
211
        else
 
212
                return false;
 
213
}
 
214
 
 
215
size_t getFilesInDir(const char *directory, std::vector<FileInfo> *files, const char *filter, int flags) {
 
216
        size_t foundEntries = 0;
 
217
        std::set<std::string> filters;
 
218
        std::string tmp;
 
219
        if (filter) {
 
220
                while (*filter) {
 
221
                        if (*filter == ':') {
 
222
                                filters.insert(tmp);
 
223
                                tmp = "";
 
224
                        } else {
 
225
                                tmp.push_back(*filter);
 
226
                        }
 
227
                        filter++;
 
228
                }
 
229
        }
 
230
        if (tmp.size())
 
231
                filters.insert(tmp);
 
232
#ifdef _WIN32
 
233
        // Find the first file in the directory.
 
234
        WIN32_FIND_DATA ffd;
 
235
#ifdef UNICODE
 
236
 
 
237
        HANDLE hFind = FindFirstFile((ConvertUTF8ToWString(directory) + L"\\*").c_str(), &ffd);
 
238
#else
 
239
        HANDLE hFind = FindFirstFile((std::string(directory) + "\\*").c_str(), &ffd);
 
240
#endif
 
241
        if (hFind == INVALID_HANDLE_VALUE) {
 
242
                FindClose(hFind);
 
243
                return 0;
 
244
        }
 
245
        // windows loop
 
246
        do
 
247
        {
 
248
                const std::string virtualName = ConvertWStringToUTF8(ffd.cFileName);
 
249
#else
 
250
        struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; };
 
251
        struct dirent_large diren;
 
252
        struct dirent *result = NULL;
 
253
 
 
254
        //std::string directoryWithSlash = directory;
 
255
        //if (directoryWithSlash.back() != '/')
 
256
        //      directoryWithSlash += "/";
 
257
 
 
258
        DIR *dirp = opendir(directory);
 
259
        if (!dirp)
 
260
                return 0;
 
261
        // non windows loop
 
262
        while (!readdir_r(dirp, (dirent*) &diren, &result) && result)
 
263
        {
 
264
                const std::string virtualName(result->d_name);
 
265
#endif
 
266
                // check for "." and ".."
 
267
                if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
 
268
                        ((virtualName[0] == '.') && (virtualName[1] == '.') && 
 
269
                        (virtualName[2] == '\0')))
 
270
                        continue;
 
271
 
 
272
                // Remove dotfiles (optional with flag.)
 
273
                if (!(flags & GETFILES_GETHIDDEN) && virtualName[0] == '.')
 
274
                        continue;
 
275
 
 
276
                FileInfo info;
 
277
                info.name = virtualName;
 
278
                std::string dir = directory;
 
279
 
 
280
                // Only append a slash if there isn't one on the end.
 
281
                size_t lastSlash = dir.find_last_of("/");
 
282
                if (lastSlash != (dir.length() - 1))
 
283
                        dir.append("/");
 
284
 
 
285
                info.fullName = dir + virtualName;
 
286
                info.isDirectory = isDirectory(info.fullName);
 
287
                info.exists = true;
 
288
                info.size = 0;
 
289
                if (!info.isDirectory) {
 
290
                        std::string ext = getFileExtension(info.fullName);
 
291
                        if (filter) {
 
292
                                if (filters.find(ext) == filters.end())
 
293
                                        continue;
 
294
                        }
 
295
                }
 
296
 
 
297
                if (files)
 
298
                        files->push_back(info);
 
299
                foundEntries++;
 
300
#ifdef _WIN32
 
301
        } while (FindNextFile(hFind, &ffd) != 0);
 
302
        FindClose(hFind);
 
303
#else
 
304
        }
 
305
        closedir(dirp);
 
306
#endif
 
307
        if (files)
 
308
                std::sort(files->begin(), files->end());
 
309
        return foundEntries;
 
310
}
 
311
 
 
312
#ifdef _WIN32
 
313
// Returns a vector with the device names
 
314
std::vector<std::string> getWindowsDrives()
 
315
{
 
316
        std::vector<std::string> drives;
 
317
 
 
318
        const DWORD buffsize = GetLogicalDriveStrings(0, NULL);
 
319
        std::vector<TCHAR> buff(buffsize);
 
320
        if (GetLogicalDriveStrings(buffsize, buff.data()) == buffsize - 1)
 
321
        {
 
322
                auto drive = buff.data();
 
323
                while (*drive)
 
324
                {
 
325
                        std::string str(ConvertWStringToUTF8(drive));
 
326
                        str.pop_back(); // we don't want the final backslash
 
327
                        str += "/";
 
328
                        drives.push_back(str);
 
329
                        
 
330
                        // advance to next drive
 
331
                        while (*drive++) {}
 
332
                }
 
333
        }
 
334
        return drives;
 
335
}
 
336
#endif