summaryrefslogtreecommitdiff
path: root/src/common/file_util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/file_util.cpp')
-rw-r--r--src/common/file_util.cpp910
1 files changed, 910 insertions, 0 deletions
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
new file mode 100644
index 000000000..8b47cb3e5
--- /dev/null
+++ b/src/common/file_util.cpp
@@ -0,0 +1,910 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5
6#include "common.h"
7#include "common_paths.h"
8#include "file_util.h"
9#include "string_util.h"
10
11#ifdef _WIN32
12#include <windows.h>
13#include <shlobj.h> // for SHGetFolderPath
14#include <shellapi.h>
15#include <commdlg.h> // for GetSaveFileName
16#include <io.h>
17#include <direct.h> // getcwd
18#else
19#include <sys/param.h>
20#include <sys/types.h>
21#include <dirent.h>
22#include <errno.h>
23#include <stdlib.h>
24#endif
25
26#if defined(__APPLE__)
27#include <CoreFoundation/CFString.h>
28#include <CoreFoundation/CFURL.h>
29#include <CoreFoundation/CFBundle.h>
30#endif
31
32#include <algorithm>
33#include <sys/stat.h>
34
35#include "string_util.h"
36
37#ifndef S_ISDIR
38#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
39#endif
40
41#ifdef BSD4_4
42#define stat64 stat
43#define fstat64 fstat
44#endif
45
46// This namespace has various generic functions related to files and paths.
47// The code still needs a ton of cleanup.
48// REMEMBER: strdup considered harmful!
49namespace File
50{
51
52// Remove any ending forward slashes from directory paths
53// Modifies argument.
54static void StripTailDirSlashes(std::string &fname)
55{
56 if (fname.length() > 1)
57 {
58 size_t i = fname.length() - 1;
59 while (fname[i] == DIR_SEP_CHR)
60 fname[i--] = '\0';
61 }
62 return;
63}
64
65// Returns true if file filename exists
66bool Exists(const std::string &filename)
67{
68 struct stat64 file_info;
69
70 std::string copy(filename);
71 StripTailDirSlashes(copy);
72
73#ifdef _WIN32
74 int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info);
75#else
76 int result = stat64(copy.c_str(), &file_info);
77#endif
78
79 return (result == 0);
80}
81
82// Returns true if filename is a directory
83bool IsDirectory(const std::string &filename)
84{
85 struct stat64 file_info;
86
87 std::string copy(filename);
88 StripTailDirSlashes(copy);
89
90#ifdef _WIN32
91 int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info);
92#else
93 int result = stat64(copy.c_str(), &file_info);
94#endif
95
96 if (result < 0) {
97 WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s",
98 filename.c_str(), GetLastErrorMsg());
99 return false;
100 }
101
102 return S_ISDIR(file_info.st_mode);
103}
104
105// Deletes a given filename, return true on success
106// Doesn't supports deleting a directory
107bool Delete(const std::string &filename)
108{
109 INFO_LOG(COMMON, "Delete: file %s", filename.c_str());
110
111 // Return true because we care about the file no
112 // being there, not the actual delete.
113 if (!Exists(filename))
114 {
115 WARN_LOG(COMMON, "Delete: %s does not exist", filename.c_str());
116 return true;
117 }
118
119 // We can't delete a directory
120 if (IsDirectory(filename))
121 {
122 WARN_LOG(COMMON, "Delete failed: %s is a directory", filename.c_str());
123 return false;
124 }
125
126#ifdef _WIN32
127 if (!DeleteFile(UTF8ToTStr(filename).c_str()))
128 {
129 WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s",
130 filename.c_str(), GetLastErrorMsg());
131 return false;
132 }
133#else
134 if (unlink(filename.c_str()) == -1) {
135 WARN_LOG(COMMON, "Delete: unlink failed on %s: %s",
136 filename.c_str(), GetLastErrorMsg());
137 return false;
138 }
139#endif
140
141 return true;
142}
143
144// Returns true if successful, or path already exists.
145bool CreateDir(const std::string &path)
146{
147 INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str());
148#ifdef _WIN32
149 if (::CreateDirectory(UTF8ToTStr(path).c_str(), NULL))
150 return true;
151 DWORD error = GetLastError();
152 if (error == ERROR_ALREADY_EXISTS)
153 {
154 WARN_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str());
155 return true;
156 }
157 ERROR_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: %i", path.c_str(), error);
158 return false;
159#else
160 if (mkdir(path.c_str(), 0755) == 0)
161 return true;
162
163 int err = errno;
164
165 if (err == EEXIST)
166 {
167 WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str());
168 return true;
169 }
170
171 ERROR_LOG(COMMON, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err));
172 return false;
173#endif
174}
175
176// Creates the full path of fullPath returns true on success
177bool CreateFullPath(const std::string &fullPath)
178{
179 int panicCounter = 100;
180 INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str());
181
182 if (File::Exists(fullPath))
183 {
184 INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str());
185 return true;
186 }
187
188 size_t position = 0;
189 while (true)
190 {
191 // Find next sub path
192 position = fullPath.find(DIR_SEP_CHR, position);
193
194 // we're done, yay!
195 if (position == fullPath.npos)
196 return true;
197
198 // Include the '/' so the first call is CreateDir("/") rather than CreateDir("")
199 std::string const subPath(fullPath.substr(0, position + 1));
200 if (!File::IsDirectory(subPath))
201 File::CreateDir(subPath);
202
203 // A safety check
204 panicCounter--;
205 if (panicCounter <= 0)
206 {
207 ERROR_LOG(COMMON, "CreateFullPath: directory structure is too deep");
208 return false;
209 }
210 position++;
211 }
212}
213
214
215// Deletes a directory filename, returns true on success
216bool DeleteDir(const std::string &filename)
217{
218 INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str());
219
220 // check if a directory
221 if (!File::IsDirectory(filename))
222 {
223 ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str());
224 return false;
225 }
226
227#ifdef _WIN32
228 if (::RemoveDirectory(UTF8ToTStr(filename).c_str()))
229 return true;
230#else
231 if (rmdir(filename.c_str()) == 0)
232 return true;
233#endif
234 ERROR_LOG(COMMON, "DeleteDir: %s: %s", filename.c_str(), GetLastErrorMsg());
235
236 return false;
237}
238
239// renames file srcFilename to destFilename, returns true on success
240bool Rename(const std::string &srcFilename, const std::string &destFilename)
241{
242 INFO_LOG(COMMON, "Rename: %s --> %s",
243 srcFilename.c_str(), destFilename.c_str());
244 if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
245 return true;
246 ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s",
247 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
248 return false;
249}
250
251// copies file srcFilename to destFilename, returns true on success
252bool Copy(const std::string &srcFilename, const std::string &destFilename)
253{
254 INFO_LOG(COMMON, "Copy: %s --> %s",
255 srcFilename.c_str(), destFilename.c_str());
256#ifdef _WIN32
257 if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE))
258 return true;
259
260 ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s",
261 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
262 return false;
263#else
264
265 // buffer size
266#define BSIZE 1024
267
268 char buffer[BSIZE];
269
270 // Open input file
271 FILE *input = fopen(srcFilename.c_str(), "rb");
272 if (!input)
273 {
274 ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s",
275 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
276 return false;
277 }
278
279 // open output file
280 FILE *output = fopen(destFilename.c_str(), "wb");
281 if (!output)
282 {
283 fclose(input);
284 ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s",
285 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
286 return false;
287 }
288
289 // copy loop
290 while (!feof(input))
291 {
292 // read input
293 int rnum = fread(buffer, sizeof(char), BSIZE, input);
294 if (rnum != BSIZE)
295 {
296 if (ferror(input) != 0)
297 {
298 ERROR_LOG(COMMON,
299 "Copy: failed reading from source, %s --> %s: %s",
300 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
301 goto bail;
302 }
303 }
304
305 // write output
306 int wnum = fwrite(buffer, sizeof(char), rnum, output);
307 if (wnum != rnum)
308 {
309 ERROR_LOG(COMMON,
310 "Copy: failed writing to output, %s --> %s: %s",
311 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
312 goto bail;
313 }
314 }
315 // close files
316 fclose(input);
317 fclose(output);
318 return true;
319bail:
320 if (input)
321 fclose(input);
322 if (output)
323 fclose(output);
324 return false;
325#endif
326}
327
328// Returns the size of filename (64bit)
329u64 GetSize(const std::string &filename)
330{
331 if (!Exists(filename))
332 {
333 WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.c_str());
334 return 0;
335 }
336
337 if (IsDirectory(filename))
338 {
339 WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str());
340 return 0;
341 }
342
343 struct stat64 buf;
344#ifdef _WIN32
345 if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0)
346#else
347 if (stat64(filename.c_str(), &buf) == 0)
348#endif
349 {
350 DEBUG_LOG(COMMON, "GetSize: %s: %lld",
351 filename.c_str(), (long long)buf.st_size);
352 return buf.st_size;
353 }
354
355 ERROR_LOG(COMMON, "GetSize: Stat failed %s: %s",
356 filename.c_str(), GetLastErrorMsg());
357 return 0;
358}
359
360// Overloaded GetSize, accepts file descriptor
361u64 GetSize(const int fd)
362{
363 struct stat64 buf;
364 if (fstat64(fd, &buf) != 0) {
365 ERROR_LOG(COMMON, "GetSize: stat failed %i: %s",
366 fd, GetLastErrorMsg());
367 return 0;
368 }
369 return buf.st_size;
370}
371
372// Overloaded GetSize, accepts FILE*
373u64 GetSize(FILE *f)
374{
375 // can't use off_t here because it can be 32-bit
376 u64 pos = ftello(f);
377 if (fseeko(f, 0, SEEK_END) != 0) {
378 ERROR_LOG(COMMON, "GetSize: seek failed %p: %s",
379 f, GetLastErrorMsg());
380 return 0;
381 }
382 u64 size = ftello(f);
383 if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) {
384 ERROR_LOG(COMMON, "GetSize: seek failed %p: %s",
385 f, GetLastErrorMsg());
386 return 0;
387 }
388 return size;
389}
390
391// creates an empty file filename, returns true on success
392bool CreateEmptyFile(const std::string &filename)
393{
394 INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str());
395
396 if (!File::IOFile(filename, "wb"))
397 {
398 ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s",
399 filename.c_str(), GetLastErrorMsg());
400 return false;
401 }
402
403 return true;
404}
405
406
407// Scans the directory tree gets, starting from _Directory and adds the
408// results into parentEntry. Returns the number of files+directories found
409u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
410{
411 INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str());
412 // How many files + directories we found
413 u32 foundEntries = 0;
414#ifdef _WIN32
415 // Find the first file in the directory.
416 WIN32_FIND_DATA ffd;
417
418 HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd);
419 if (hFind == INVALID_HANDLE_VALUE)
420 {
421 FindClose(hFind);
422 return foundEntries;
423 }
424 // windows loop
425 do
426 {
427 FSTEntry entry;
428 const std::string virtualName(TStrToUTF8(ffd.cFileName));
429#else
430 struct dirent dirent, *result = NULL;
431
432 DIR *dirp = opendir(directory.c_str());
433 if (!dirp)
434 return 0;
435
436 // non windows loop
437 while (!readdir_r(dirp, &dirent, &result) && result)
438 {
439 FSTEntry entry;
440 const std::string virtualName(result->d_name);
441#endif
442 // check for "." and ".."
443 if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
444 ((virtualName[0] == '.') && (virtualName[1] == '.') &&
445 (virtualName[2] == '\0')))
446 continue;
447 entry.virtualName = virtualName;
448 entry.physicalName = directory;
449 entry.physicalName += DIR_SEP + entry.virtualName;
450
451 if (IsDirectory(entry.physicalName.c_str()))
452 {
453 entry.isDirectory = true;
454 // is a directory, lets go inside
455 entry.size = ScanDirectoryTree(entry.physicalName, entry);
456 foundEntries += (u32)entry.size;
457 }
458 else
459 { // is a file
460 entry.isDirectory = false;
461 entry.size = GetSize(entry.physicalName.c_str());
462 }
463 ++foundEntries;
464 // Push into the tree
465 parentEntry.children.push_back(entry);
466#ifdef _WIN32
467 } while (FindNextFile(hFind, &ffd) != 0);
468 FindClose(hFind);
469#else
470 }
471 closedir(dirp);
472#endif
473 // Return number of entries found.
474 return foundEntries;
475}
476
477
478// Deletes the given directory and anything under it. Returns true on success.
479bool DeleteDirRecursively(const std::string &directory)
480{
481 INFO_LOG(COMMON, "DeleteDirRecursively: %s", directory.c_str());
482#ifdef _WIN32
483 // Find the first file in the directory.
484 WIN32_FIND_DATA ffd;
485 HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd);
486
487 if (hFind == INVALID_HANDLE_VALUE)
488 {
489 FindClose(hFind);
490 return false;
491 }
492
493 // windows loop
494 do
495 {
496 const std::string virtualName(TStrToUTF8(ffd.cFileName));
497#else
498 struct dirent dirent, *result = NULL;
499 DIR *dirp = opendir(directory.c_str());
500 if (!dirp)
501 return false;
502
503 // non windows loop
504 while (!readdir_r(dirp, &dirent, &result) && result)
505 {
506 const std::string virtualName = result->d_name;
507#endif
508
509 // check for "." and ".."
510 if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
511 ((virtualName[0] == '.') && (virtualName[1] == '.') &&
512 (virtualName[2] == '\0')))
513 continue;
514
515 std::string newPath = directory + DIR_SEP_CHR + virtualName;
516 if (IsDirectory(newPath))
517 {
518 if (!DeleteDirRecursively(newPath))
519 {
520 #ifndef _WIN32
521 closedir(dirp);
522 #endif
523
524 return false;
525 }
526 }
527 else
528 {
529 if (!File::Delete(newPath))
530 {
531 #ifndef _WIN32
532 closedir(dirp);
533 #endif
534
535 return false;
536 }
537 }
538
539#ifdef _WIN32
540 } while (FindNextFile(hFind, &ffd) != 0);
541 FindClose(hFind);
542#else
543 }
544 closedir(dirp);
545#endif
546 File::DeleteDir(directory);
547
548 return true;
549}
550
551// Create directory and copy contents (does not overwrite existing files)
552void CopyDir(const std::string &source_path, const std::string &dest_path)
553{
554#ifndef _WIN32
555 if (source_path == dest_path) return;
556 if (!File::Exists(source_path)) return;
557 if (!File::Exists(dest_path)) File::CreateFullPath(dest_path);
558
559 struct dirent dirent, *result = NULL;
560 DIR *dirp = opendir(source_path.c_str());
561 if (!dirp) return;
562
563 while (!readdir_r(dirp, &dirent, &result) && result)
564 {
565 const std::string virtualName(result->d_name);
566 // check for "." and ".."
567 if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
568 ((virtualName[0] == '.') && (virtualName[1] == '.') &&
569 (virtualName[2] == '\0')))
570 continue;
571
572 std::string source, dest;
573 source = source_path + virtualName;
574 dest = dest_path + virtualName;
575 if (IsDirectory(source))
576 {
577 source += '/';
578 dest += '/';
579 if (!File::Exists(dest)) File::CreateFullPath(dest);
580 CopyDir(source, dest);
581 }
582 else if (!File::Exists(dest)) File::Copy(source, dest);
583 }
584 closedir(dirp);
585#endif
586}
587
588// Returns the current directory
589std::string GetCurrentDir()
590{
591 char *dir;
592 // Get the current working directory (getcwd uses malloc)
593 if (!(dir = __getcwd(NULL, 0))) {
594
595 ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s",
596 GetLastErrorMsg());
597 return NULL;
598 }
599 std::string strDir = dir;
600 free(dir);
601 return strDir;
602}
603
604// Sets the current directory to the given directory
605bool SetCurrentDir(const std::string &directory)
606{
607 return __chdir(directory.c_str()) == 0;
608}
609
610#if defined(__APPLE__)
611std::string GetBundleDirectory()
612{
613 CFURLRef BundleRef;
614 char AppBundlePath[MAXPATHLEN];
615 // Get the main bundle for the app
616 BundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
617 CFStringRef BundlePath = CFURLCopyFileSystemPath(BundleRef, kCFURLPOSIXPathStyle);
618 CFStringGetFileSystemRepresentation(BundlePath, AppBundlePath, sizeof(AppBundlePath));
619 CFRelease(BundleRef);
620 CFRelease(BundlePath);
621
622 return AppBundlePath;
623}
624#endif
625
626#ifdef _WIN32
627std::string& GetExeDirectory()
628{
629 static std::string DolphinPath;
630 if (DolphinPath.empty())
631 {
632 TCHAR Dolphin_exe_Path[2048];
633 GetModuleFileName(NULL, Dolphin_exe_Path, 2048);
634 DolphinPath = TStrToUTF8(Dolphin_exe_Path);
635 DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\'));
636 }
637 return DolphinPath;
638}
639#endif
640
641std::string GetSysDirectory()
642{
643 std::string sysDir;
644
645#if defined (__APPLE__)
646 sysDir = GetBundleDirectory();
647 sysDir += DIR_SEP;
648 sysDir += SYSDATA_DIR;
649#else
650 sysDir = SYSDATA_DIR;
651#endif
652 sysDir += DIR_SEP;
653
654 INFO_LOG(COMMON, "GetSysDirectory: Setting to %s:", sysDir.c_str());
655 return sysDir;
656}
657
658// Returns a string with a Dolphin data dir or file in the user's home
659// directory. To be used in "multi-user" mode (that is, installed).
660const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath)
661{
662 static std::string paths[NUM_PATH_INDICES];
663
664 // Set up all paths and files on the first run
665 if (paths[D_USER_IDX].empty())
666 {
667#ifdef _WIN32
668 paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
669#else
670 if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
671 paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
672 else
673 paths[D_USER_IDX] = std::string(getenv("HOME") ?
674 getenv("HOME") : getenv("PWD") ?
675 getenv("PWD") : "") + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP;
676#endif
677
678 paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
679 paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
680 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
681 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
682 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
683 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
684 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
685 paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
686 paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
687 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
688 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
689 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
690 paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
691 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
692 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
693 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
694 }
695
696 if (!newPath.empty())
697 {
698 if (!File::IsDirectory(newPath))
699 {
700 WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str());
701 return paths[DirIDX];
702 }
703 else
704 {
705 paths[DirIDX] = newPath;
706 }
707
708 switch (DirIDX)
709 {
710 case D_ROOT_IDX:
711 paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
712 paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP;
713 paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF;
714 break;
715
716 case D_USER_IDX:
717 paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
718 paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
719 paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
720 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
721 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
722 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
723 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
724 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
725 paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
726 paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
727 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
728 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
729 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
730 paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
731 paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP;
732 paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
733 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
734 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
735 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
736 break;
737
738 case D_CONFIG_IDX:
739 paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
740 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
741 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
742 break;
743
744 case D_DUMP_IDX:
745 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
746 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
747 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
748 break;
749
750 case D_LOGS_IDX:
751 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
752 }
753 }
754
755 return paths[DirIDX];
756}
757
758//std::string GetThemeDir(const std::string& theme_name)
759//{
760// std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/";
761//
762//#if !defined(_WIN32)
763// // If theme does not exist in user's dir load from shared directory
764// if (!File::Exists(dir))
765// dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/";
766//#endif
767//
768// return dir;
769//}
770
771bool WriteStringToFile(bool text_file, const std::string &str, const char *filename)
772{
773 return File::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
774}
775
776bool ReadFileToString(bool text_file, const char *filename, std::string &str)
777{
778 File::IOFile file(filename, text_file ? "r" : "rb");
779 auto const f = file.GetHandle();
780
781 if (!f)
782 return false;
783
784 str.resize(static_cast<u32>(GetSize(f)));
785 return file.ReadArray(&str[0], str.size());
786}
787
788IOFile::IOFile()
789 : m_file(NULL), m_good(true)
790{}
791
792IOFile::IOFile(std::FILE* file)
793 : m_file(file), m_good(true)
794{}
795
796IOFile::IOFile(const std::string& filename, const char openmode[])
797 : m_file(NULL), m_good(true)
798{
799 Open(filename, openmode);
800}
801
802IOFile::~IOFile()
803{
804 Close();
805}
806
807IOFile::IOFile(IOFile&& other)
808 : m_file(NULL), m_good(true)
809{
810 Swap(other);
811}
812
813IOFile& IOFile::operator=(IOFile&& other)
814{
815 Swap(other);
816 return *this;
817}
818
819void IOFile::Swap(IOFile& other)
820{
821 std::swap(m_file, other.m_file);
822 std::swap(m_good, other.m_good);
823}
824
825bool IOFile::Open(const std::string& filename, const char openmode[])
826{
827 Close();
828#ifdef _WIN32
829 _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str());
830#else
831 m_file = fopen(filename.c_str(), openmode);
832#endif
833
834 m_good = IsOpen();
835 return m_good;
836}
837
838bool IOFile::Close()
839{
840 if (!IsOpen() || 0 != std::fclose(m_file))
841 m_good = false;
842
843 m_file = NULL;
844 return m_good;
845}
846
847std::FILE* IOFile::ReleaseHandle()
848{
849 std::FILE* const ret = m_file;
850 m_file = NULL;
851 return ret;
852}
853
854void IOFile::SetHandle(std::FILE* file)
855{
856 Close();
857 Clear();
858 m_file = file;
859}
860
861u64 IOFile::GetSize()
862{
863 if (IsOpen())
864 return File::GetSize(m_file);
865 else
866 return 0;
867}
868
869bool IOFile::Seek(s64 off, int origin)
870{
871 if (!IsOpen() || 0 != fseeko(m_file, off, origin))
872 m_good = false;
873
874 return m_good;
875}
876
877u64 IOFile::Tell()
878{
879 if (IsOpen())
880 return ftello(m_file);
881 else
882 return -1;
883}
884
885bool IOFile::Flush()
886{
887 if (!IsOpen() || 0 != std::fflush(m_file))
888 m_good = false;
889
890 return m_good;
891}
892
893bool IOFile::Resize(u64 size)
894{
895 if (!IsOpen() || 0 !=
896#ifdef _WIN32
897 // ector: _chsize sucks, not 64-bit safe
898 // F|RES: changed to _chsize_s. i think it is 64-bit safe
899 _chsize_s(_fileno(m_file), size)
900#else
901 // TODO: handle 64bit and growing
902 ftruncate(fileno(m_file), size)
903#endif
904 )
905 m_good = false;
906
907 return m_good;
908}
909
910} // namespace