Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
vfs_util.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2010 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * helper functions for directory access
25  */
26 
27 #include "precompiled.h"
28 #include "lib/file/vfs/vfs_util.h"
29 
30 #include <queue>
31 #include <cstring>
32 #include <cstdio>
33 
34 #include "lib/sysdep/filesystem.h"
35 #include "lib/regex.h"
36 
37 
38 namespace vfs {
39 
40 Status GetPathnames(const PIVFS& fs, const VfsPath& path, const wchar_t* filter, VfsPaths& pathnames)
41 {
42  std::vector<CFileInfo> files;
43  RETURN_STATUS_IF_ERR(fs->GetDirectoryEntries(path, &files, 0));
44 
45  pathnames.clear();
46  pathnames.reserve(files.size());
47 
48  for(size_t i = 0; i < files.size(); i++)
49  {
50  if(match_wildcard(files[i].Name().string().c_str(), filter))
51  pathnames.push_back(path / files[i].Name());
52  }
53 
54  return INFO::OK;
55 }
56 
57 
58 Status ForEachFile(const PIVFS& fs, const VfsPath& startPath, FileCallback cb, uintptr_t cbData, const wchar_t* pattern, size_t flags)
59 {
60  // (declare here to avoid reallocations)
61  CFileInfos files; DirectoryNames subdirectoryNames;
62 
63  // (a FIFO queue is more efficient than recursion because it uses less
64  // stack space and avoids seeks due to breadth-first traversal.)
65  std::queue<VfsPath> pendingDirectories;
66  pendingDirectories.push(startPath/"");
67  while(!pendingDirectories.empty())
68  {
69  const VfsPath& path = pendingDirectories.front();
70 
71  RETURN_STATUS_IF_ERR(fs->GetDirectoryEntries(path, &files, &subdirectoryNames));
72 
73  for(size_t i = 0; i < files.size(); i++)
74  {
75  const CFileInfo fileInfo = files[i];
76  if(!match_wildcard(fileInfo.Name().string().c_str(), pattern))
77  continue;
78 
79  const VfsPath pathname(path / fileInfo.Name()); // (CFileInfo only stores the name)
80  cb(pathname, fileInfo, cbData);
81  }
82 
83  if(!(flags & DIR_RECURSIVE))
84  break;
85 
86  for(size_t i = 0; i < subdirectoryNames.size(); i++)
87  pendingDirectories.push(path / subdirectoryNames[i]/"");
88  pendingDirectories.pop();
89  }
90 
91  return INFO::OK;
92 }
93 
94 
95 void NextNumberedFilename(const PIVFS& fs, const VfsPath& pathnameFormat, size_t& nextNumber, VfsPath& nextPathname)
96 {
97  // (first call only:) scan directory and set nextNumber according to
98  // highest matching filename found. this avoids filling "holes" in
99  // the number series due to deleted files, which could be confusing.
100  // example: add 1st and 2nd; [exit] delete 1st; [restart]
101  // add 3rd -> without this measure it would get number 1, not 3.
102  if(nextNumber == 0)
103  {
104  const VfsPath nameFormat = pathnameFormat.Filename();
105  const VfsPath path = pathnameFormat.Parent()/"";
106 
107  size_t maxNumber = 0;
108  CFileInfos files;
109  fs->GetDirectoryEntries(path, &files, 0);
110  for(size_t i = 0; i < files.size(); i++)
111  {
112  int number;
113  if(swscanf_s(files[i].Name().string().c_str(), nameFormat.string().c_str(), &number) == 1)
114  maxNumber = std::max(size_t(number), maxNumber);
115  }
116 
117  nextNumber = maxNumber+1;
118  }
119 
120  // now increment number until that file doesn't yet exist.
121  // this is fairly slow, but typically only happens once due
122  // to scan loop above. (we still need to provide for looping since
123  // someone may have added files in the meantime)
124  // we don't bother with binary search - this isn't a bottleneck.
125  do
126  {
127  wchar_t pathnameBuf[PATH_MAX];
128  swprintf_s(pathnameBuf, ARRAY_SIZE(pathnameBuf), pathnameFormat.string().c_str(), nextNumber++);
129  nextPathname = pathnameBuf;
130  }
131  while(fs->GetFileInfo(nextPathname, 0) == INFO::OK);
132 }
133 
134 } // namespace vfs
#define swscanf_s
Definition: secure_crt.h:119
Path Filename() const
Definition: path.h:158
const Status OK
Definition: status.h:386
void NextNumberedFilename(const PIVFS &fs, const VfsPath &pathnameFormat, size_t &nextNumber, VfsPath &nextPathname)
Determine the next available pathname with a given format.
Definition: vfs_util.cpp:95
const OsPath & Name() const
Definition: file_system.h:53
shared_ptr< IVFS > PIVFS
Definition: vfs.h:226
Path Parent() const
Definition: path.h:150
Status(* FileCallback)(const VfsPath &pathname, const CFileInfo &fileInfo, const uintptr_t cbData)
called for files in a directory.
Definition: vfs_util.h:49
int match_wildcard(const wchar_t *s, const wchar_t *w)
see if string matches pattern.
Definition: regex.cpp:28
int swprintf_s(wchar_t *buf, size_t max_chars, const wchar_t *fmt,...) WPRINTF_ARGS(3)
#define ARRAY_SIZE(name)
Definition: path.h:75
const String & string() const
Definition: path.h:123
i64 Status
Error handling system.
Definition: status.h:171
#define PATH_MAX
Definition: wposix_types.h:101
Status ForEachFile(const PIVFS &fs, const VfsPath &startPath, FileCallback cb, uintptr_t cbData, const wchar_t *pattern, size_t flags)
call back for each file in a directory tree
Definition: vfs_util.cpp:58
std::vector< OsPath > DirectoryNames
Definition: file_system.h:77
std::vector< VfsPath > VfsPaths
Definition: vfs_path.h:42
std::vector< CFileInfo > CFileInfos
Definition: file_system.h:76
Status GetPathnames(const PIVFS &fs, const VfsPath &path, const wchar_t *filter, VfsPaths &pathnames)
Definition: vfs_util.cpp:40
#define RETURN_STATUS_IF_ERR(expression)
Definition: status.h:276