ManaPlus
files.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2013-2019 The ManaPlus Developers
4  * Copyright (C) 2019-2021 Andrei Karas
5  *
6  * This file is part of The ManaPlus Client.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "fs/files.h"
23 
24 #include "fs/mkdir.h"
25 #if defined(ANDROID) || defined(__native_client__)
26 #include "fs/paths.h"
27 
28 #include "fs/virtfs/fs.h"
29 #include "fs/virtfs/tools.h"
30 #include "fs/virtfs/list.h"
31 #endif // defined(ANDROID) || defined(__native_client__)
32 
33 #if defined(ANDROID) || defined(__native_client__)
34 #include "utils/foreach.h"
35 #endif // defined(ANDROID) || defined(__native_client__)
36 
37 #include "utils/checkutils.h"
38 #include "utils/stringutils.h"
39 
40 #include <dirent.h>
41 #include <fstream>
42 #include <sys/stat.h>
43 
44 #include "debug.h"
45 
46 extern const char *dirSeparator;
47 
48 #ifdef ANDROID
49 void Files::extractLocale()
50 {
51  // in future need also remove all locales in local dir
52 
53  const std::string fileName2 = pathJoin(getenv("APPDIR"), "locale.zip");
54  VirtFs::mountZip(fileName2, Append_false);
55 
56  const std::string localDir = std::string(getenv("APPDIR"));
57  VirtFs::List *const rootDirs = VirtFs::enumerateFiles("locale");
58  FOR_EACH (StringVectCIter, i, rootDirs->names)
59  {
60  const std::string dir = pathJoin("locale", *i);
61  if (VirtFs::isDirectory(dir))
62  {
63  const std::string moFile = dir + "/LC_MESSAGES/manaplus.mo";
64  if (VirtFs::exists((moFile)))
65  {
66  const std::string localFile = pathJoin(localDir, moFile);
67  const std::string localDir2 = pathJoin(localDir,
68  dir,
69  "LC_MESSAGES");
70  mkdir_r(localDir2.c_str());
71  copyVirtFsFile(moFile, localFile);
72  }
73  }
74  }
75  VirtFs::freeList(rootDirs);
76  VirtFs::unmountZip(fileName2);
77  remove(fileName2.c_str());
78 }
79 #endif // ANDROID
80 
81 #if defined(ANDROID) || defined(__native_client__)
82 
83 namespace
84 {
85 #ifdef ANDROID
86  int mFilesCount = 0;
87 #endif // ANDROID
88 
89  Files::CopyFileCallbackPtr mCallbackPtr = nullptr;
90 } // namespace
91 
92 void Files::setCopyCallBack(Files::CopyFileCallbackPtr callback)
93 {
94  mCallbackPtr = callback;
95 }
96 
97 void Files::copyVirtFsFile(const std::string &restrict inFile,
98  const std::string &restrict outFile)
99 {
100  int size = 0;
101  const char *const buf = VirtFs::loadFile(inFile, size);
102  FILE *const file = fopen(outFile.c_str(), "w");
103  fwrite(buf, 1, size, file);
104  fclose(file);
105  delete [] buf;
106 #ifdef ANDROID
107  if (mCallbackPtr)
108  {
109  mCallbackPtr(mFilesCount);
110  mFilesCount ++;
111  }
112 #endif // ANDROID
113 }
114 
115 void Files::copyVirtFsDir(const std::string &restrict inDir,
116  const std::string &restrict outDir)
117 {
118  mkdir_r(outDir.c_str());
119  VirtFs::List *const files = VirtFs::enumerateFiles(inDir);
120  FOR_EACH (StringVectCIter, i, files->names)
121  {
122  const std::string file = pathJoin(inDir, *i);
123  const std::string outDir2 = pathJoin(outDir, *i);
124  if (VirtFs::isDirectory(file))
125  copyVirtFsDir(file, outDir2);
126  else
127  copyVirtFsFile(file, outDir2);
128  }
129  VirtFs::freeList(files);
130 }
131 
132 #endif // ANDROID __native_client__
133 
134 int Files::renameFile(const std::string &restrict srcName,
135  const std::string &restrict dstName)
136 {
137 #if defined __native_client__
138  FILE *srcFile = fopen(srcName.c_str(), "rb");
139  if (srcFile == nullptr)
140  return -1;
141  FILE *dstFile = fopen(dstName.c_str(), "w+b");
142  if (dstFile == nullptr)
143  {
144  fclose(srcFile);
145  return -1;
146  }
147 
148  const int chunkSize = 500000;
149  char *buf = new char[chunkSize];
150  size_t sz = 0;
151  while ((sz = fread(buf, 1, chunkSize, srcFile)))
152  {
153  if (fwrite(buf, 1, sz, dstFile) != sz)
154  {
155  delete [] buf;
156  fclose(srcFile);
157  fclose(dstFile);
158  ::remove(dstName.c_str());
159  return -1;
160  }
161  }
162 
163  delete [] buf;
164  fclose(srcFile);
165  fclose(dstFile);
166  if (!::remove(srcName.c_str()))
167  return 0;
168 
169  return -1;
170 #else // defined __native_client__
171 
172  return ::rename(srcName.c_str(), dstName.c_str());
173 #endif // defined __native_client__
174 }
175 
176 int Files::copyFile(const std::string &restrict srcName,
177  const std::string &restrict dstName)
178 {
179  FILE *srcFile = fopen(srcName.c_str(), "rb");
180  if (srcFile == nullptr)
181  return -1;
182  FILE *dstFile = fopen(dstName.c_str(), "w+b");
183  if (dstFile == nullptr)
184  {
185  fclose(srcFile);
186  return -1;
187  }
188 
189  const int chunkSize = 512000;
190  char *buf = new char[chunkSize];
191  size_t sz = 0;
192  while ((sz = fread(buf, 1, chunkSize, srcFile)) != 0U)
193  {
194  if (fwrite(buf, 1, sz, dstFile) != sz)
195  {
196  delete [] buf;
197  fclose(srcFile);
198  fclose(dstFile);
199  return -1;
200  }
201  }
202 
203  delete [] buf;
204  fclose(srcFile);
205  fclose(dstFile);
206  return 0;
207 }
208 
209 bool Files::existsLocal(const std::string &path)
210 {
211  struct stat statbuf;
212 #ifdef WIN32
213  // in windows path\file.ext\ by default detected as exists
214  // if file.ext is not directory, need return false
215  const bool res = (stat(path.c_str(), &statbuf) == 0);
216  if (res == false)
217  return false;
218  if ((findLast(path, "/") == true || findLast(path, "\\") == true) &&
219  S_ISDIR(statbuf.st_mode) == 0)
220  {
221  return false;
222  }
223  return true;
224 #else // WIN32
225  return stat(path.c_str(), &statbuf) == 0;
226 #endif // WIN32
227 }
228 
229 bool Files::loadTextFileLocal(const std::string &fileName,
230  StringVect &lines)
231 {
232  std::ifstream file;
233  char line[501];
234 
235  file.open(fileName.c_str(), std::ios::in);
236 
237  if (!file.is_open())
238  {
239  reportAlways("Couldn't load text file: %s",
240  fileName.c_str())
241  return false;
242  }
243 
244  while (file.getline(line, 500))
245  lines.push_back(line);
246 
247  return true;
248 }
249 
250 void Files::saveTextFile(const std::string &path,
251  const std::string &restrict name,
252  const std::string &restrict text)
253 {
254  if (mkdir_r(path.c_str()) == 0)
255  {
256  std::ofstream file;
257  std::string fileName = pathJoin(path, name);
258  file.open(fileName.c_str(), std::ios::out);
259  if (file.is_open())
260  {
261  file << text << std::endl;
262  }
263  else
264  {
265  reportAlways("Error opening file for writing: %s",
266  fileName.c_str())
267  }
268  file.close();
269  }
270 }
271 
272 void Files::deleteFilesInDirectory(std::string path)
273 {
274  path = pathJoin(path, dirSeparator);
275  const dirent *next_file = nullptr;
276  DIR *const dir = opendir(path.c_str());
277 
278  if (dir != nullptr)
279  {
280  while ((next_file = readdir(dir)) != nullptr)
281  {
282  const std::string file = next_file->d_name;
283  if (file != "." && file != "..")
284  remove((path + file).c_str());
285  }
286  closedir(dir);
287  }
288 }
289 
291  std::string path,
292  const bool skipSymlinks A_WIN_UNUSED)
293 {
294  if (findLast(path, dirSeparator) == false)
295  path += dirSeparator;
296  DIR *const dir = opendir(path.c_str());
297 
298  if (dir != nullptr)
299  {
300  const dirent *next_file = nullptr;
301  while ((next_file = readdir(dir)) != nullptr)
302  {
303  const std::string file = next_file->d_name;
304  if (file == "." || file == "..")
305  continue;
306 #ifndef WIN32
307  if (skipSymlinks == true)
308  {
309  struct stat statbuf;
310  if (lstat(path.c_str(), &statbuf) == 0 &&
311  S_ISLNK(statbuf.st_mode) != 0)
312  {
313  continue;
314  }
315  }
316 #endif // WIN32
317  files.push_back(file);
318  }
319  closedir(dir);
320  }
321 }
const bool Append_false
Definition: append.h:30
#define reportAlways(...)
Definition: checkutils.h:253
const char * dirSeparator
Definition: fs.cpp:43
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
#define restrict
Definition: localconsts.h:165
#define A_WIN_UNUSED
Definition: localconsts.h:353
int mkdir_r(const char *const pathname)
Create a directory, making leading components first if necessary.
Definition: mkdir.cpp:109
int size()
Definition: emotedb.cpp:306
bool loadTextFileLocal(const std::string &fileName, StringVect &lines)
Definition: files.cpp:229
int renameFile(const std::string &pFrom, const std::string &pTo)
Definition: files.cpp:134
int copyFile(const std::string &pFrom, const std::string &pTo)
Definition: files.cpp:176
void deleteFilesInDirectory(std::string path)
Definition: files.cpp:272
void enumFiles(StringVect &files, std::string path, const bool skipSymlinks)
Definition: files.cpp:290
bool existsLocal(const std::string &path)
Definition: files.cpp:209
void saveTextFile(const std::string &path, const std::string &name, const std::string &text)
Definition: files.cpp:250
bool remove(const std::string &filename)
Definition: fs.cpp:780
void freeList(List *const handle)
Definition: fs.cpp:269
bool mountZip(std::string newDir, const Append append)
Definition: fs.cpp:590
bool unmountZip(std::string oldDir)
Definition: fs.cpp:675
bool isDirectory(std::string name)
Definition: fs.cpp:239
const char * loadFile(std::string filename, int &fileSize)
Definition: fs.cpp:859
List * enumerateFiles(std::string dirName)
Definition: fs.cpp:147
bool exists(std::string name)
Definition: fs.cpp:124
bool findLast(const std::string &str1, const std::string &str2)
std::string pathJoin(std::string str1, const std::string &str2)
StringVect::const_iterator StringVectCIter
Definition: stringvector.h:31
std::vector< std::string > StringVect
Definition: stringvector.h:29
StringVect names
Definition: list.h:40
std::string fileName
Definition: testmain.cpp:39