Line data Source code
1 : /* Copyright (C) 2022 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "precompiled.h"
19 :
20 : #include "Filesystem.h"
21 :
22 : #include "lib/sysdep/dir_watch.h"
23 : #include "lib/utf8.h"
24 : #include "ps/CLogger.h"
25 : #include "ps/CStr.h"
26 : #include "ps/Profile.h"
27 :
28 : #include <boost/filesystem.hpp>
29 :
30 1 : PIVFS g_VFS;
31 :
32 1 : static std::vector<std::pair<FileReloadFunc, void*> > g_ReloadFuncs;
33 :
34 2488 : bool VfsFileExists(const VfsPath& pathname)
35 : {
36 2488 : return g_VFS->GetFileInfo(pathname, 0) == INFO::OK;
37 : }
38 :
39 14 : bool VfsDirectoryExists(const VfsPath& pathname)
40 : {
41 14 : ENSURE(pathname.IsDirectory());
42 14 : return g_VFS->GetDirectoryEntries(pathname, NULL, NULL) == INFO::OK;
43 : }
44 :
45 39 : void RegisterFileReloadFunc(FileReloadFunc func, void* obj)
46 : {
47 39 : g_ReloadFuncs.emplace_back(func, obj);
48 39 : }
49 :
50 39 : void UnregisterFileReloadFunc(FileReloadFunc func, void* obj)
51 : {
52 78 : g_ReloadFuncs.erase(std::remove(g_ReloadFuncs.begin(), g_ReloadFuncs.end(), std::make_pair(func, obj)));
53 39 : }
54 :
55 : // try to skip unnecessary work by ignoring uninteresting notifications.
56 0 : static bool CanIgnore(const DirWatchNotification& notification)
57 : {
58 : // ignore directories
59 0 : const OsPath& pathname = notification.Pathname();
60 0 : if(pathname.IsDirectory())
61 0 : return true;
62 :
63 : // ignore uninteresting file types (e.g. temp files, or the
64 : // hundreds of XMB files that are generated from XML)
65 0 : const OsPath extension = pathname.Extension();
66 0 : const wchar_t* extensionsToIgnore[] = { L".xmb", L".tmp" };
67 0 : for(size_t i = 0; i < ARRAY_SIZE(extensionsToIgnore); i++)
68 : {
69 0 : if(extension == extensionsToIgnore[i])
70 0 : return true;
71 : }
72 :
73 0 : return false;
74 : }
75 :
76 0 : Status ReloadChangedFiles()
77 : {
78 0 : PROFILE3("hotload");
79 :
80 0 : std::vector<DirWatchNotification> notifications;
81 0 : RETURN_STATUS_IF_ERR(dir_watch_Poll(notifications));
82 0 : for(size_t i = 0; i < notifications.size(); i++)
83 : {
84 0 : if(!CanIgnore(notifications[i]))
85 : {
86 0 : VfsPath pathname;
87 0 : RETURN_STATUS_IF_ERR(g_VFS->GetVirtualPath(notifications[i].Pathname(), pathname));
88 0 : RETURN_STATUS_IF_ERR(g_VFS->RemoveFile(pathname));
89 0 : RETURN_STATUS_IF_ERR(g_VFS->RepopulateDirectory(pathname.Parent()/""));
90 :
91 : // Tell each hotloadable system about this file change:
92 :
93 0 : for (size_t j = 0; j < g_ReloadFuncs.size(); ++j)
94 0 : g_ReloadFuncs[j].first(g_ReloadFuncs[j].second, pathname);
95 : }
96 : }
97 0 : return INFO::OK;
98 : }
99 :
100 80 : std::wstring GetWstringFromWpath(const fs::wpath& path)
101 : {
102 : #if BOOST_FILESYSTEM_VERSION == 3
103 80 : return path.wstring();
104 : #else
105 : return path.string();
106 : #endif
107 : }
108 :
109 :
110 2479 : CVFSFile::CVFSFile()
111 2479 : : m_BufferSize(0)
112 : {
113 2479 : }
114 :
115 2479 : CVFSFile::~CVFSFile()
116 : {
117 2479 : }
118 :
119 2479 : PSRETURN CVFSFile::Load(const PIVFS& vfs, const VfsPath& filename, bool log /* = true */)
120 : {
121 : // Load should never be called more than once, so complain
122 2479 : if (m_Buffer)
123 : {
124 0 : DEBUG_WARN_ERR(ERR::LOGIC);
125 0 : return PSRETURN_CVFSFile_AlreadyLoaded;
126 : }
127 :
128 2479 : Status ret = vfs->LoadFile(filename, m_Buffer, m_BufferSize);
129 2479 : if (ret != INFO::OK)
130 : {
131 6 : if (log)
132 6 : LOGERROR("CVFSFile: file %s couldn't be opened (vfs_load: %lld)", filename.string8(), (long long)ret);
133 6 : m_Buffer.reset();
134 6 : m_BufferSize = 0;
135 6 : return PSRETURN_CVFSFile_LoadFailed;
136 : }
137 :
138 2473 : return PSRETURN_OK;
139 : }
140 :
141 2473 : const u8* CVFSFile::GetBuffer() const
142 : {
143 2473 : return m_Buffer.get();
144 : }
145 :
146 4888 : size_t CVFSFile::GetBufferSize() const
147 : {
148 4888 : return m_BufferSize;
149 : }
150 :
151 5 : CStr CVFSFile::GetAsString() const
152 : {
153 5 : return std::string((char*)GetBuffer(), GetBufferSize());
154 : }
155 :
156 2415 : CStr CVFSFile::DecodeUTF8() const
157 : {
158 2415 : const u8* buffer = GetBuffer();
159 :
160 : // Detect if there's a UTF-8 BOM and strip it
161 2415 : if (GetBufferSize() >= 3 && buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF)
162 : {
163 0 : return std::string(&buffer[3], buffer + GetBufferSize());
164 : }
165 : else
166 : {
167 2415 : return std::string(buffer, buffer + GetBufferSize());
168 : }
169 3 : }
|