You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Framework/AzFramework/AzFramework/Archive/ZipDirFind.cpp

222 lines
6.2 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/IO/SystemFile.h>
#include <AzCore/std/string/wildcard.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzFramework/Archive/ZipFileFormat.h>
#include <AzFramework/Archive/ZipDirStructures.h>
#include <AzFramework/Archive/ZipDirCache.h>
#include <AzFramework/Archive/ZipDirFind.h>
namespace AZ::IO::ZipDir
{
bool FindFile::FindFirst(AZ::IO::PathView szWildcard)
{
if (!PreFind(szWildcard))
{
return false;
}
// finally, this is the name of the file
m_itFile = m_pDirHeader->GetFileBegin();
return SkipNonMatchingFiles();
}
bool FindDir::FindFirst(AZ::IO::PathView szWildcard)
{
if (!PreFind(szWildcard))
{
return false;
}
// finally, this is the name of the file
m_itDir = m_pDirHeader->GetDirBegin();
return SkipNonMatchingDirs();
}
// matches the file wildcard in the m_szWildcard to the given file/dir name
bool FindData::MatchWildcard(AZ::IO::PathView szName)
{
return szName.Match(m_szWildcard.Native());
}
FileEntry* FindFile::FindExact(AZ::IO::PathView szPath)
{
if (!PreFind(szPath))
{
return nullptr;
}
FileEntryTree::FileMap::iterator itFile = m_pDirHeader->FindFile(m_szWildcard);
if (itFile == m_pDirHeader->GetFileEnd())
{
m_pDirHeader = nullptr; // we didn't find it, fail the search
return nullptr;
}
m_itFile = itFile;
return m_pDirHeader->GetFileEntry(m_itFile);
}
FileEntryTree* FindDir::FindExact(AZ::IO::PathView szPath)
{
if (!PreFind(szPath))
{
return nullptr;
}
// the wild card will contain the target directory name
return m_pDirHeader->FindDir(m_szWildcard);
}
//////////////////////////////////////////////////////////////////////////
// after this call returns successfully (with true returned), the m_szWildcard
// contains the file name/glob and m_pDirHeader contains the directory where
// the file (s) are to be found
bool FindData::PreFind(AZ::IO::PathView pathGlob)
{
if (!m_pRoot)
{
return false;
}
FileEntryTree* entryTreeHeader = m_pRoot;
// If there is a root path in the glob path, attempt to locate it from the root
if (AZ::IO::PathView rootPath = m_szWildcard.RootPath(); !rootPath.empty())
{
FileEntryTree* dirEntry = entryTreeHeader->FindDir(rootPath);
if (dirEntry == nullptr)
{
return false;
}
entryTreeHeader = dirEntry->GetDirectory();
pathGlob = pathGlob.RelativePath();
}
AZ::IO::PathView filenameSegment = pathGlob;
// Recurse through the directories within the file tree for each remaining parent path segment
// of pathGlob parameter
auto parentPathIter = pathGlob.begin();
for (auto filenamePathIter = parentPathIter == pathGlob.end() ? pathGlob.end() : AZStd::next(parentPathIter, 1);
filenamePathIter != pathGlob.end(); ++parentPathIter, ++filenamePathIter)
{
FileEntryTree* dirEntry = entryTreeHeader->FindDir(*parentPathIter);
if (dirEntry == nullptr)
{
return false;
}
entryTreeHeader = dirEntry->GetDirectory();
filenameSegment = *filenamePathIter;
}
// At this point the all the intermediate directories have been found
// so update the directory header to point at the last file entry tree
m_pDirHeader = entryTreeHeader;
m_szWildcard = filenameSegment;
return true;
}
// goes on to the next entry
bool FindFile::FindNext()
{
if (m_pDirHeader && m_itFile != m_pDirHeader->GetFileEnd())
{
++m_itFile;
return SkipNonMatchingFiles();
}
else
{
return false;
}
}
// goes on to the next entry
bool FindDir::FindNext()
{
if (m_pDirHeader && m_itDir != m_pDirHeader->GetDirEnd())
{
++m_itDir;
return SkipNonMatchingDirs();
}
else
{
return false;
}
}
bool FindFile::SkipNonMatchingFiles()
{
AZ_Assert(m_pDirHeader, "Directory header cannot be nullptr when skipping files.");
for (; m_itFile != m_pDirHeader->GetFileEnd(); ++m_itFile)
{
if (MatchWildcard(GetFileName()))
{
return true;
}
}
// we didn't find anything other file else
return false;
}
bool FindDir::SkipNonMatchingDirs()
{
AZ_Assert(m_pDirHeader, "Directory header is nullptr. Directories cannot be skipped");
for (; m_itDir != m_pDirHeader->GetDirEnd(); ++m_itDir)
{
if (MatchWildcard(GetDirName()))
{
return true;
}
}
// we didn't find anything other file else
return false;
}
FileEntry* FindFile::GetFileEntry()
{
return m_pDirHeader && m_itFile != m_pDirHeader->GetFileEnd() ? m_pDirHeader->GetFileEntry(m_itFile) : nullptr;
}
FileEntryTree* FindDir::GetDirEntry()
{
return m_pDirHeader && m_itDir != m_pDirHeader->GetDirEnd() ? m_pDirHeader->GetDirEntry(m_itDir) : nullptr;
}
AZStd::string_view FindFile::GetFileName()
{
if (m_pDirHeader && m_itFile != m_pDirHeader->GetFileEnd())
{
return m_pDirHeader->GetFileName(m_itFile);
}
else
{
return ""; // default name
}
}
AZStd::string_view FindDir::GetDirName()
{
if (m_pDirHeader && m_itDir != m_pDirHeader->GetDirEnd())
{
return m_pDirHeader->GetDirName(m_itDir);
}
else
{
return ""; // default name
}
}
}