mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 21:34:08 -07:00
also rename wchar -> utf8 to avoid conflict with <wchar.h> (requires rebuild of workspace) (unfortunately copying history fails to "502 bad gateway"; had to delete old + add new independently) This was SVN commit r7340.
152 lines
5 KiB
C++
152 lines
5 KiB
C++
/* Copyright (c) 2010 Wildfire Games
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
/*
|
|
* populate VFS directories with files
|
|
*/
|
|
|
|
#include "precompiled.h"
|
|
#include "lib/file/vfs/vfs_populate.h"
|
|
|
|
#include "lib/path_util.h"
|
|
#include "lib/file/archive/archive_zip.h"
|
|
#include "lib/file/vfs/vfs_tree.h"
|
|
#include "lib/file/vfs/vfs_lookup.h"
|
|
#include "lib/file/vfs/vfs.h" // error codes
|
|
|
|
|
|
static std::vector<const VfsFile*> s_looseFiles;
|
|
static size_t s_numArchivedFiles;
|
|
|
|
// helper class that allows breaking up the logic into sub-functions without
|
|
// always having to pass directory/realDirectory as parameters.
|
|
class PopulateHelper
|
|
{
|
|
NONCOPYABLE(PopulateHelper);
|
|
public:
|
|
PopulateHelper(VfsDirectory* directory, const PRealDirectory& realDirectory)
|
|
: m_directory(directory), m_realDirectory(realDirectory)
|
|
{
|
|
}
|
|
|
|
LibError AddEntries() const
|
|
{
|
|
FileInfos files; files.reserve(100);
|
|
DirectoryNames subdirectoryNames; subdirectoryNames.reserve(20);
|
|
RETURN_ERR(GetDirectoryEntries(m_realDirectory->Path(), &files, &subdirectoryNames));
|
|
RETURN_ERR(AddFiles(files));
|
|
AddSubdirectories(subdirectoryNames);
|
|
return INFO::OK;
|
|
}
|
|
|
|
private:
|
|
void AddFile(const FileInfo& fileInfo) const
|
|
{
|
|
const VfsFile file(fileInfo.Name(), (size_t)fileInfo.Size(), fileInfo.MTime(), m_realDirectory->Priority(), m_realDirectory);
|
|
const VfsFile* pfile = m_directory->AddFile(file);
|
|
|
|
// notify archive builder that this file could be archived but
|
|
// currently isn't; if there are too many of these, archive will
|
|
// be rebuilt.
|
|
// note: check if archivable to exclude stuff like screenshots
|
|
// from counting towards the threshold.
|
|
if(m_realDirectory->Flags() & VFS_MOUNT_ARCHIVABLE)
|
|
s_looseFiles.push_back(pfile);
|
|
}
|
|
|
|
static void AddArchiveFile(const VfsPath& pathname, const FileInfo& fileInfo, PIArchiveFile archiveFile, uintptr_t cbData)
|
|
{
|
|
PopulateHelper* this_ = (PopulateHelper*)cbData;
|
|
|
|
// (we have to create missing subdirectoryNames because archivers
|
|
// don't always place directory entries before their files)
|
|
const size_t flags = VFS_LOOKUP_ADD;
|
|
VfsDirectory* directory;
|
|
WARN_ERR(vfs_Lookup(pathname, this_->m_directory, directory, 0, flags));
|
|
const VfsFile file(fileInfo.Name(), (size_t)fileInfo.Size(), fileInfo.MTime(), this_->m_realDirectory->Priority(), archiveFile);
|
|
directory->AddFile(file);
|
|
s_numArchivedFiles++;
|
|
}
|
|
|
|
LibError AddFiles(const FileInfos& files) const
|
|
{
|
|
const fs::wpath path(m_realDirectory->Path());
|
|
|
|
for(size_t i = 0; i < files.size(); i++)
|
|
{
|
|
const fs::wpath pathname = path/files[i].Name();
|
|
const std::wstring extension = fs::extension(pathname);
|
|
if(wcscasecmp(extension.c_str(), L"zip") == 0)
|
|
{
|
|
PIArchiveReader archiveReader = CreateArchiveReader_Zip(pathname);
|
|
RETURN_ERR(archiveReader->ReadEntries(AddArchiveFile, (uintptr_t)this));
|
|
}
|
|
else // regular (non-archive) file
|
|
AddFile(files[i]);
|
|
}
|
|
|
|
return INFO::OK;
|
|
}
|
|
|
|
void AddSubdirectories(const DirectoryNames& subdirectoryNames) const
|
|
{
|
|
for(size_t i = 0; i < subdirectoryNames.size(); i++)
|
|
{
|
|
// skip version control directories - this avoids cluttering the
|
|
// VFS with hundreds of irrelevant files.
|
|
if(wcscasecmp(subdirectoryNames[i].c_str(), L".svn") == 0)
|
|
continue;
|
|
|
|
VfsDirectory* subdirectory = m_directory->AddSubdirectory(subdirectoryNames[i]);
|
|
PRealDirectory realDirectory = CreateRealSubdirectory(m_realDirectory, subdirectoryNames[i]);
|
|
vfs_Attach(subdirectory, realDirectory);
|
|
}
|
|
}
|
|
|
|
VfsDirectory* const m_directory;
|
|
PRealDirectory m_realDirectory;
|
|
};
|
|
|
|
|
|
LibError vfs_Populate(VfsDirectory* directory)
|
|
{
|
|
if(!directory->ShouldPopulate())
|
|
return INFO::OK;
|
|
|
|
const PRealDirectory& realDirectory = directory->AssociatedDirectory();
|
|
|
|
if(realDirectory->Flags() & VFS_MOUNT_WATCH)
|
|
realDirectory->Watch();
|
|
|
|
PopulateHelper helper(directory, realDirectory);
|
|
RETURN_ERR(helper.AddEntries());
|
|
|
|
return INFO::OK;
|
|
}
|
|
|
|
|
|
LibError vfs_Attach(VfsDirectory* directory, const PRealDirectory& realDirectory)
|
|
{
|
|
RETURN_ERR(vfs_Populate(directory));
|
|
directory->SetAssociatedDirectory(realDirectory);
|
|
return INFO::OK;
|
|
}
|