C++ 如何将FindXFile样式的API封装到C++;?
我正在努力包装C++ 如何将FindXFile样式的API封装到C++;?,c++,winapi,iterator,C++,Winapi,Iterator,我正在努力包装FindFirstFile/FindNextFile循环的丑陋内部(尽管我的问题适用于其他类似的API,如RegEnumKeyEx或RegEnumValue等)内部迭代器,其工作方式类似于标准模板库的istream\u迭代器s 我这里有两个问题。第一个是大多数“foreach”样式循环的终止条件。STL风格的迭代器通常使用操作符=在for的退出条件内,即 std::vector<int> test; for(std::vector<int>::iterato
FindFirstFile
/FindNextFile
循环的丑陋内部(尽管我的问题适用于其他类似的API,如RegEnumKeyEx
或RegEnumValue
等)内部迭代器,其工作方式类似于标准模板库的istream\u迭代器
s
我这里有两个问题。第一个是大多数“foreach”样式循环的终止条件。STL风格的迭代器通常使用操作符=代码>在for的退出条件内,即
std::vector<int> test;
for(std::vector<int>::iterator it = test.begin(); it != test.end(); it++) {
//Do stuff
}
编辑:调用者看起来像:
SomeIterator x = ??; //Construct somehow
while(x.next()) {
//Do stuff
}
谢谢
比利3
EDIT2:我已经修复了一些bug并编写了一些测试
实施:
#pragma once
#include <queue>
#include <string>
#include <boost/noncopyable.hpp>
#include <boost/make_shared.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <Windows.h>
#include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
#include "../Exception.hpp"
namespace WindowsAPI { namespace FileSystem {
template <typename Filter_T = AllResults, typename Recurse_T = NonRecursiveEnumeration>
class DirectoryIterator;
//For unit testing
struct RealFindXFileFunctions
{
static HANDLE FindFirst(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) {
return FindFirstFile(lpFileName, lpFindFileData);
};
static BOOL FindNext(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) {
return FindNextFile(hFindFile, lpFindFileData);
};
static BOOL Close(HANDLE hFindFile) {
return FindClose(hFindFile);
};
};
inline std::wstring::const_iterator GetLastSlash(std::wstring const&pathSpec) {
return std::find(pathSpec.rbegin(), pathSpec.rend(), L'\\').base();
}
class Win32FindData {
WIN32_FIND_DATA internalData;
std::wstring rootPath;
public:
Win32FindData(const std::wstring& root, const WIN32_FIND_DATA& data) :
rootPath(root), internalData(data) {};
DWORD GetAttributes() const {
return internalData.dwFileAttributes;
};
bool IsDirectory() const {
return (internalData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
};
bool IsFile() const {
return !IsDirectory();
};
unsigned __int64 GetSize() const {
ULARGE_INTEGER intValue;
intValue.LowPart = internalData.nFileSizeLow;
intValue.HighPart = internalData.nFileSizeHigh;
return intValue.QuadPart;
};
std::wstring GetFolderPath() const {
return rootPath;
};
std::wstring GetFileName() const {
return internalData.cFileName;
};
std::wstring GetFullFileName() const {
return rootPath + L"\\" + internalData.cFileName;
};
std::wstring GetShortFileName() const {
return internalData.cAlternateFileName;
};
FILETIME GetCreationTime() const {
return internalData.ftCreationTime;
};
FILETIME GetLastAccessTime() const {
return internalData.ftLastAccessTime;
};
FILETIME GetLastWriteTime() const {
return internalData.ftLastWriteTime;
};
};
template <typename FindXFileFunctions_T>
class BasicNonRecursiveEnumeration : public boost::noncopyable
{
WIN32_FIND_DATAW currentData;
HANDLE hFind;
std::wstring currentDirectory;
void IncrementCurrentDirectory() {
if (hFind == INVALID_HANDLE_VALUE) return;
BOOL success =
FindXFileFunctions_T::FindNext(hFind, ¤tData);
if (success)
return;
DWORD error = GetLastError();
if (error == ERROR_NO_MORE_FILES) {
FindXFileFunctions_T::Close(hFind);
hFind = INVALID_HANDLE_VALUE;
} else {
WindowsApiException::Throw(error);
}
};
bool IsValidDotDirectory()
{
return !Valid() &&
(!wcscmp(currentData.cFileName, L".") || !wcscmp(currentData.cFileName, L".."));
};
void IncrementPastDotDirectories() {
while (IsValidDotDirectory()) {
IncrementCurrentDirectory();
}
};
void PerformFindFirstFile(std::wstring const&pathSpec)
{
hFind = FindXFileFunctions_T::FindFirst(pathSpec.c_str(), ¤tData);
if (Valid()
&& GetLastError() != ERROR_PATH_NOT_FOUND
&& GetLastError() != ERROR_FILE_NOT_FOUND)
WindowsApiException::ThrowFromLastError();
};
public:
BasicNonRecursiveEnumeration() : hFind(INVALID_HANDLE_VALUE) {};
BasicNonRecursiveEnumeration(const std::wstring& pathSpec) :
hFind(INVALID_HANDLE_VALUE) {
std::wstring::const_iterator lastSlash = GetLastSlash(pathSpec);
if (lastSlash != pathSpec.begin())
currentDirectory.assign(pathSpec.begin(), lastSlash-1);
PerformFindFirstFile(pathSpec);
IncrementPastDotDirectories();
};
bool equal(const BasicNonRecursiveEnumeration<FindXFileFunctions_T>& other) const {
if (this == &other)
return true;
return hFind == other.hFind;
};
Win32FindData dereference() {
return Win32FindData(currentDirectory, currentData);
};
void increment() {
IncrementCurrentDirectory();
};
bool Valid() {
return hFind == INVALID_HANDLE_VALUE;
};
virtual ~BasicNonRecursiveEnumeration() {
if (!Valid())
FindXFileFunctions_T::Close(hFind);
};
};
typedef BasicNonRecursiveEnumeration<RealFindXFileFunctions> NonRecursiveEnumeration;
template <typename FindXFileFunctions_T>
class BasicRecursiveEnumeration : public boost::noncopyable
{
std::wstring fileSpec;
std::deque<std::deque<Win32FindData> > enumeratedData;
void EnumerateDirectory(const std::wstring& nextPathSpec) {
std::deque<Win32FindData> newDeck;
BasicNonRecursiveEnumeration<FindXFileFunctions_T> begin(nextPathSpec), end;
for(; !begin.equal(end); begin.increment()) {
newDeck.push_back(begin.dereference());
}
if (!newDeck.empty()) {
enumeratedData.push_back(std::deque<Win32FindData>()); //Swaptimization
enumeratedData.back().swap(newDeck);
}
};
void PerformIncrement() {
if (enumeratedData.empty()) return;
if (enumeratedData.back().front().IsDirectory()) {
std::wstring nextSpec(enumeratedData.back().front().GetFullFileName());
nextSpec.append(L"\\*");
enumeratedData.back().pop_front();
EnumerateDirectory(nextSpec);
} else {
enumeratedData.back().pop_front();
}
while (Valid() && enumeratedData.back().empty())
enumeratedData.pop_back();
}
bool CurrentPositionNoMatchFileSpec() const
{
return !enumeratedData.empty() && !PathMatchSpecW(enumeratedData.back().front().GetFileName().c_str(), fileSpec.c_str());
}
public:
BasicRecursiveEnumeration() {};
BasicRecursiveEnumeration(const std::wstring& pathSpec) {
std::wstring::const_iterator lastSlash = GetLastSlash(pathSpec);
if (lastSlash == pathSpec.begin()) {
fileSpec = pathSpec;
EnumerateDirectory(L"*");
} else {
fileSpec.assign(lastSlash, pathSpec.end());
std::wstring firstQuery(pathSpec.begin(), lastSlash);
firstQuery.push_back(L'*');
EnumerateDirectory(firstQuery);
while (CurrentPositionNoMatchFileSpec())
PerformIncrement();
}
};
void increment() {
do
{
PerformIncrement();
} while (CurrentPositionNoMatchFileSpec());
};
bool equal(const BasicRecursiveEnumeration<FindXFileFunctions_T>& other) const {
if (!Valid())
return !other.Valid();
if (!other.Valid())
return false;
return this == &other;
};
Win32FindData dereference() const {
return enumeratedData.back().front();
};
bool Valid() const {
return !enumeratedData.empty();
};
};
typedef BasicRecursiveEnumeration<RealFindXFileFunctions> RecursiveEnumeration;
struct AllResults
{
bool operator()(const Win32FindData&) {
return true;
};
};
struct FilesOnly
{
bool operator()(const Win32FindData& arg) {
return arg.IsFile();
};
};
template <typename Filter_T, typename Recurse_T>
class DirectoryIterator :
public boost::iterator_facade<
DirectoryIterator<Filter_T, Recurse_T>,
Win32FindData,
std::input_iterator_tag,
Win32FindData
>
{
friend class boost::iterator_core_access;
boost::shared_ptr<Recurse_T> impl;
Filter_T filter;
void increment() {
do {
impl->increment();
} while (impl->Valid() && !filter(impl->dereference()));
};
bool equal(const DirectoryIterator& other) const {
return impl->equal(*other.impl);
};
Win32FindData dereference() const {
return impl->dereference();
};
public:
DirectoryIterator(Filter_T functor = Filter_T()) :
impl(boost::make_shared<Recurse_T>()),
filter(functor) {
};
explicit DirectoryIterator(const std::wstring& pathSpec, Filter_T functor = Filter_T()) :
impl(boost::make_shared<Recurse_T>(pathSpec)),
filter(functor) {
};
};
}}
#pragma一次
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#pragma注释(lib,“shlwapi.lib”)
#包括“./Exception.hpp”
命名空间WindowsAPI{命名空间文件系统{
模板
类目录迭代器;
//用于单元测试
结构RealFindXFileFunctions
{
静态句柄FindFirst(LPCWSTR lpFileName,LPWIN32_FIND_DATAW lpFindFileData){
返回FindFirstFile(lpFileName,lpFindFileData);
};
静态BOOL FindNext(句柄hFindFile,LPWIN32\u FIND\u DATAW lpFindFileData){
返回FindNextFile(hFindFile,lpFindFileData);
};
静态布尔关闭(句柄hFindFile){
返回FindClose(hFindFile);
};
};
内联std::wstring::const_迭代器GetLastSlash(std::wstring const&pathSpec){
返回std::find(pathSpec.rbegin(),pathSpec.rend(),L'\\').base();
}
类Win32FindData{
WIN32_查找_数据内部数据;
std::wstring根路径;
公众:
Win32FindData(const std::wstring和root,const WIN32_FIND_DATA和DATA):
根路径(根),内部数据(数据){};
DWORD GetAttributes()常量{
返回internalData.dwFileAttributes;
};
bool IsDirectory()常量{
返回(internalData.dwFileAttributes和文件属性目录)!=0;
};
bool IsFile()常量{
return!IsDirectory();
};
未签名的\uuu int64 GetSize()常量{
ULARGE_整数值;
intValue.LowPart=internalData.nFileSizeLow;
intValue.HighPart=internalData.nFileSizeHigh;
返回intValue.QuadPart;
};
std::wstring GetFolderPath()常量{
返回根路径;
};
std::wstring GetFileName()常量{
返回internalData.cFileName;
};
std::wstring GetFullFileName()常量{
返回rootPath+L“\\”+internalData.cFileName;
};
std::wstring GetShortFileName()常量{
返回internalData.cAlternateFileName;
};
FILETIME GetCreationTime()常量{
返回internalData.ftCreationTime;
};
FILETIME GetLastAccessTime()常量{
返回internalData.ftLastAccessTime;
};
FILETIME GetLastWriteTime()常量{
返回internalData.ftLastWriteTime;
};
};
模板
类BasicNonRecursiveEnumeration:公共boost::不可复制
{
WIN32_FIND_DATAW currentData;
处理高频风;
std::wstring当前目录;
void IncrementCurrentDirectory(){
if(hFind==无效的句柄值)返回;
布尔成功=
FindXFileFunctions\u T::FindNext(hFind和currentData);
如果(成功)
返回;
DWORD error=GetLastError();
如果(错误==错误\u没有\u更多\u文件){
FindXFileFunctions\u T::Close(hFind);
hFind=无效的句柄值;
}否则{
WindowsApiException::抛出(错误);
}
};
bool IsValidDotDirectory()
{
return!Valid()&&
(!wcscmp(currentData.cFileName,L.”)| |!wcscmp(currentData.cFileName,L.”);
};
void incrementPastDotDirectory(){
while(IsValidDotDirectory()){
IncrementCurrentDirectory();
}
};
作废PerformFindFirstFile(标准::wstring常量和路径规范)
{
hFind=FindXFileFunctions\u T::FindFirst(pathSpec.c\u str(),¤tData);
if(Valid()
&&GetLastError()!=找不到错误路径
&&GetLastError()!=错误(未找到文件)
WindowsApiException::ThrowFromLastError();
};
公众:
BasicNonRecursiveEnumeration():hFind(无效的句柄值){};
基本非递归枚举(常量std::wstring和pathSpec):
hFind(无效的句柄值){
std::wstring::const_迭代器lastsslash=getlastsslash(路径规范);
if(lastSlash!=pathSpec.begin())
currentDirectory.assign(pathSpec.begin(),lastsslash-1);
PerformFindFirstFile(路径规范);
递增的PastDotDirectory();
};
布尔相等(常数基本非递归枚举和其他)常数{
如果(此==&其他)
返回true;
返回hFind==other.hFind;
};
Win32FindData取消引用(){
返回Win32FindData(currentDirectory,currentData);
};
无效增量(){
IncrementCurrentDirectory();
};
bool Valid(){
返回hFind==无效的\u句柄\u值;
};
虚拟~BasicNonRecursiveEnumeration(){
如果(!Valid())
FindXFileFunctions\u T::Close(hFind);
};
};
typedef BasicNonRecursiveEnumeration非递归枚举;
模板
类BasicRecursiveEnumeration:公共boost::不可复制
{
std::wstring fileSpec;
std::deque Enumeratedata;
无效枚举目录(const std::wstring和nextPathSpec){
标准:德克纽戴克;
基本非递归枚举开始(nextPathSpec),结束;
对于(;!begin.equal(end);begin.increment()){
newDeck.push_back(begin.dereference());
}
如果(!newDeck.empty()){
enumeratedData.push_back(std::deque());//优化
enumeratedData.back().swap(newDeck);
}
};
无效性能增量(){
if(enumeratedData.empty())返回;
if(enumeratedData.back().front().IsDirectory()){
#pragma once
#include <queue>
#include <string>
#include <boost/noncopyable.hpp>
#include <boost/make_shared.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <Windows.h>
#include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
#include "../Exception.hpp"
namespace WindowsAPI { namespace FileSystem {
template <typename Filter_T = AllResults, typename Recurse_T = NonRecursiveEnumeration>
class DirectoryIterator;
//For unit testing
struct RealFindXFileFunctions
{
static HANDLE FindFirst(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) {
return FindFirstFile(lpFileName, lpFindFileData);
};
static BOOL FindNext(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) {
return FindNextFile(hFindFile, lpFindFileData);
};
static BOOL Close(HANDLE hFindFile) {
return FindClose(hFindFile);
};
};
inline std::wstring::const_iterator GetLastSlash(std::wstring const&pathSpec) {
return std::find(pathSpec.rbegin(), pathSpec.rend(), L'\\').base();
}
class Win32FindData {
WIN32_FIND_DATA internalData;
std::wstring rootPath;
public:
Win32FindData(const std::wstring& root, const WIN32_FIND_DATA& data) :
rootPath(root), internalData(data) {};
DWORD GetAttributes() const {
return internalData.dwFileAttributes;
};
bool IsDirectory() const {
return (internalData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
};
bool IsFile() const {
return !IsDirectory();
};
unsigned __int64 GetSize() const {
ULARGE_INTEGER intValue;
intValue.LowPart = internalData.nFileSizeLow;
intValue.HighPart = internalData.nFileSizeHigh;
return intValue.QuadPart;
};
std::wstring GetFolderPath() const {
return rootPath;
};
std::wstring GetFileName() const {
return internalData.cFileName;
};
std::wstring GetFullFileName() const {
return rootPath + L"\\" + internalData.cFileName;
};
std::wstring GetShortFileName() const {
return internalData.cAlternateFileName;
};
FILETIME GetCreationTime() const {
return internalData.ftCreationTime;
};
FILETIME GetLastAccessTime() const {
return internalData.ftLastAccessTime;
};
FILETIME GetLastWriteTime() const {
return internalData.ftLastWriteTime;
};
};
template <typename FindXFileFunctions_T>
class BasicNonRecursiveEnumeration : public boost::noncopyable
{
WIN32_FIND_DATAW currentData;
HANDLE hFind;
std::wstring currentDirectory;
void IncrementCurrentDirectory() {
if (hFind == INVALID_HANDLE_VALUE) return;
BOOL success =
FindXFileFunctions_T::FindNext(hFind, ¤tData);
if (success)
return;
DWORD error = GetLastError();
if (error == ERROR_NO_MORE_FILES) {
FindXFileFunctions_T::Close(hFind);
hFind = INVALID_HANDLE_VALUE;
} else {
WindowsApiException::Throw(error);
}
};
bool IsValidDotDirectory()
{
return !Valid() &&
(!wcscmp(currentData.cFileName, L".") || !wcscmp(currentData.cFileName, L".."));
};
void IncrementPastDotDirectories() {
while (IsValidDotDirectory()) {
IncrementCurrentDirectory();
}
};
void PerformFindFirstFile(std::wstring const&pathSpec)
{
hFind = FindXFileFunctions_T::FindFirst(pathSpec.c_str(), ¤tData);
if (Valid()
&& GetLastError() != ERROR_PATH_NOT_FOUND
&& GetLastError() != ERROR_FILE_NOT_FOUND)
WindowsApiException::ThrowFromLastError();
};
public:
BasicNonRecursiveEnumeration() : hFind(INVALID_HANDLE_VALUE) {};
BasicNonRecursiveEnumeration(const std::wstring& pathSpec) :
hFind(INVALID_HANDLE_VALUE) {
std::wstring::const_iterator lastSlash = GetLastSlash(pathSpec);
if (lastSlash != pathSpec.begin())
currentDirectory.assign(pathSpec.begin(), lastSlash-1);
PerformFindFirstFile(pathSpec);
IncrementPastDotDirectories();
};
bool equal(const BasicNonRecursiveEnumeration<FindXFileFunctions_T>& other) const {
if (this == &other)
return true;
return hFind == other.hFind;
};
Win32FindData dereference() {
return Win32FindData(currentDirectory, currentData);
};
void increment() {
IncrementCurrentDirectory();
};
bool Valid() {
return hFind == INVALID_HANDLE_VALUE;
};
virtual ~BasicNonRecursiveEnumeration() {
if (!Valid())
FindXFileFunctions_T::Close(hFind);
};
};
typedef BasicNonRecursiveEnumeration<RealFindXFileFunctions> NonRecursiveEnumeration;
template <typename FindXFileFunctions_T>
class BasicRecursiveEnumeration : public boost::noncopyable
{
std::wstring fileSpec;
std::deque<std::deque<Win32FindData> > enumeratedData;
void EnumerateDirectory(const std::wstring& nextPathSpec) {
std::deque<Win32FindData> newDeck;
BasicNonRecursiveEnumeration<FindXFileFunctions_T> begin(nextPathSpec), end;
for(; !begin.equal(end); begin.increment()) {
newDeck.push_back(begin.dereference());
}
if (!newDeck.empty()) {
enumeratedData.push_back(std::deque<Win32FindData>()); //Swaptimization
enumeratedData.back().swap(newDeck);
}
};
void PerformIncrement() {
if (enumeratedData.empty()) return;
if (enumeratedData.back().front().IsDirectory()) {
std::wstring nextSpec(enumeratedData.back().front().GetFullFileName());
nextSpec.append(L"\\*");
enumeratedData.back().pop_front();
EnumerateDirectory(nextSpec);
} else {
enumeratedData.back().pop_front();
}
while (Valid() && enumeratedData.back().empty())
enumeratedData.pop_back();
}
bool CurrentPositionNoMatchFileSpec() const
{
return !enumeratedData.empty() && !PathMatchSpecW(enumeratedData.back().front().GetFileName().c_str(), fileSpec.c_str());
}
public:
BasicRecursiveEnumeration() {};
BasicRecursiveEnumeration(const std::wstring& pathSpec) {
std::wstring::const_iterator lastSlash = GetLastSlash(pathSpec);
if (lastSlash == pathSpec.begin()) {
fileSpec = pathSpec;
EnumerateDirectory(L"*");
} else {
fileSpec.assign(lastSlash, pathSpec.end());
std::wstring firstQuery(pathSpec.begin(), lastSlash);
firstQuery.push_back(L'*');
EnumerateDirectory(firstQuery);
while (CurrentPositionNoMatchFileSpec())
PerformIncrement();
}
};
void increment() {
do
{
PerformIncrement();
} while (CurrentPositionNoMatchFileSpec());
};
bool equal(const BasicRecursiveEnumeration<FindXFileFunctions_T>& other) const {
if (!Valid())
return !other.Valid();
if (!other.Valid())
return false;
return this == &other;
};
Win32FindData dereference() const {
return enumeratedData.back().front();
};
bool Valid() const {
return !enumeratedData.empty();
};
};
typedef BasicRecursiveEnumeration<RealFindXFileFunctions> RecursiveEnumeration;
struct AllResults
{
bool operator()(const Win32FindData&) {
return true;
};
};
struct FilesOnly
{
bool operator()(const Win32FindData& arg) {
return arg.IsFile();
};
};
template <typename Filter_T, typename Recurse_T>
class DirectoryIterator :
public boost::iterator_facade<
DirectoryIterator<Filter_T, Recurse_T>,
Win32FindData,
std::input_iterator_tag,
Win32FindData
>
{
friend class boost::iterator_core_access;
boost::shared_ptr<Recurse_T> impl;
Filter_T filter;
void increment() {
do {
impl->increment();
} while (impl->Valid() && !filter(impl->dereference()));
};
bool equal(const DirectoryIterator& other) const {
return impl->equal(*other.impl);
};
Win32FindData dereference() const {
return impl->dereference();
};
public:
DirectoryIterator(Filter_T functor = Filter_T()) :
impl(boost::make_shared<Recurse_T>()),
filter(functor) {
};
explicit DirectoryIterator(const std::wstring& pathSpec, Filter_T functor = Filter_T()) :
impl(boost::make_shared<Recurse_T>(pathSpec)),
filter(functor) {
};
};
}}
#include <queue>
#include "../WideCharacterOutput.hpp"
#include <boost/test/unit_test.hpp>
#include "../../WindowsAPI++/FileSystem/Enumerator.hpp"
using namespace WindowsAPI::FileSystem;
struct SimpleFakeFindXFileFunctions
{
static std::deque<WIN32_FIND_DATAW> fakeData;
static std::wstring insertedFileName;
static HANDLE FindFirst(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) {
insertedFileName.assign(lpFileName);
if (fakeData.empty()) {
SetLastError(ERROR_PATH_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
*lpFindFileData = fakeData.front();
fakeData.pop_front();
return reinterpret_cast<HANDLE>(42);
};
static BOOL FindNext(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) {
BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
if (fakeData.empty()) {
SetLastError(ERROR_NO_MORE_FILES);
return 0;
}
*lpFindFileData = fakeData.front();
fakeData.pop_front();
return 1;
};
static BOOL Close(HANDLE hFindFile) {
BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
return 1;
};
};
std::deque<WIN32_FIND_DATAW> SimpleFakeFindXFileFunctions::fakeData;
std::wstring SimpleFakeFindXFileFunctions::insertedFileName;
struct ErroneousFindXFileFunctionFirst
{
static HANDLE FindFirst(LPCWSTR, LPWIN32_FIND_DATAW) {
SetLastError(ERROR_ACCESS_DENIED);
return INVALID_HANDLE_VALUE;
};
static BOOL FindNext(HANDLE hFindFile, LPWIN32_FIND_DATAW) {
BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
return 1;
};
static BOOL Close(HANDLE hFindFile) {
BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
return 1;
};
};
struct ErroneousFindXFileFunctionNext
{
static HANDLE FindFirst(LPCWSTR, LPWIN32_FIND_DATAW) {
return reinterpret_cast<HANDLE>(42);
};
static BOOL FindNext(HANDLE hFindFile, LPWIN32_FIND_DATAW) {
BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
};
static BOOL Close(HANDLE hFindFile) {
BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
return 1;
};
};
struct DirectoryIteratorTestsFixture
{
typedef SimpleFakeFindXFileFunctions fakeFunctor;
DirectoryIteratorTestsFixture() {
WIN32_FIND_DATAW test;
wcscpy_s(test.cFileName, L".");
wcscpy_s(test.cAlternateFileName, L".");
test.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
GetSystemTimeAsFileTime(&test.ftCreationTime);
test.ftLastWriteTime = test.ftCreationTime;
test.ftLastAccessTime = test.ftCreationTime;
test.nFileSizeHigh = 0;
test.nFileSizeLow = 0;
fakeFunctor::fakeData.push_back(test);
wcscpy_s(test.cFileName, L"..");
wcscpy_s(test.cAlternateFileName, L"..");
fakeFunctor::fakeData.push_back(test);
wcscpy_s(test.cFileName, L"File.txt");
wcscpy_s(test.cAlternateFileName, L"FILE.TXT");
test.nFileSizeLow = 1024;
test.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
fakeFunctor::fakeData.push_back(test);
wcscpy_s(test.cFileName, L"System32");
wcscpy_s(test.cAlternateFileName, L"SYSTEM32");
test.nFileSizeLow = 0;
test.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
fakeFunctor::fakeData.push_back(test);
};
~DirectoryIteratorTestsFixture() {
fakeFunctor::fakeData.clear();
};
};
BOOST_FIXTURE_TEST_SUITE( DirectoryIteratorTests, DirectoryIteratorTestsFixture )
template<typename fakeFunctor>
static void NonRecursiveIteratorAssertions()
{
typedef DirectoryIterator<AllResults
,BasicNonRecursiveEnumeration<SimpleFakeFindXFileFunctions> > testType;
testType begin(L"C:\\Windows\\*");
testType end;
BOOST_CHECK_EQUAL(fakeFunctor::insertedFileName, L"C:\\Windows\\*");
BOOST_CHECK(begin->GetFolderPath() == L"C:\\Windows");
BOOST_CHECK(begin->GetFileName() == L"File.txt");
BOOST_CHECK(begin->GetFullFileName() == L"C:\\Windows\\File.txt");
BOOST_CHECK(begin->GetShortFileName() == L"FILE.TXT");
BOOST_CHECK_EQUAL(begin->GetSize(), 1024);
BOOST_CHECK(begin->IsFile());
BOOST_CHECK(begin != end);
begin++;
BOOST_CHECK(begin->GetFileName() == L"System32");
BOOST_CHECK(begin->GetFullFileName() == L"C:\\Windows\\System32");
BOOST_CHECK(begin->GetShortFileName() == L"SYSTEM32");
BOOST_CHECK_EQUAL(begin->GetSize(), 0);
BOOST_CHECK(begin->IsDirectory());
begin++;
BOOST_CHECK(begin == end);
}
BOOST_AUTO_TEST_CASE( BasicEnumeration )
{
NonRecursiveIteratorAssertions<fakeFunctor>();
}
BOOST_AUTO_TEST_CASE( NoRootDirectories )
{
fakeFunctor::fakeData.pop_front();
fakeFunctor::fakeData.pop_front();
NonRecursiveIteratorAssertions<fakeFunctor>();
}
static void EmptyIteratorAssertions() {
typedef DirectoryIterator<AllResults
,BasicNonRecursiveEnumeration<SimpleFakeFindXFileFunctions> > testType;
testType begin(L"C:\\Windows\\*");
testType end;
BOOST_CHECK(begin == end);
}
BOOST_AUTO_TEST_CASE( Empty1 )
{
fakeFunctor::fakeData.clear();
EmptyIteratorAssertions();
}
BOOST_AUTO_TEST_CASE( Empty2 )
{
fakeFunctor::fakeData.erase(fakeFunctor::fakeData.begin() + 2, fakeFunctor::fakeData.end());
EmptyIteratorAssertions();
}
BOOST_AUTO_TEST_CASE( CorrectDestruction )
{
typedef DirectoryIterator<AllResults
,BasicNonRecursiveEnumeration<SimpleFakeFindXFileFunctions> > testType;
testType begin(L"C:\\Windows\\*");
testType end;
}
BOOST_AUTO_TEST_CASE( Exceptions )
{
typedef DirectoryIterator<AllResults,BasicNonRecursiveEnumeration<ErroneousFindXFileFunctionFirst> >
firstFailType;
BOOST_CHECK_THROW(firstFailType(L"C:\\Windows\\*"), WindowsAPI::ErrorAccessDeniedException);
typedef DirectoryIterator<AllResults,BasicNonRecursiveEnumeration<ErroneousFindXFileFunctionNext> >
nextFailType;
nextFailType constructedOkay(L"C:\\Windows\\*");
BOOST_CHECK_THROW(constructedOkay++, WindowsAPI::ErrorInvalidParameterException);
}
BOOST_AUTO_TEST_SUITE_END()
struct RecursiveFakeFindXFileFunctions
{
static std::deque<std::pair<std::deque<WIN32_FIND_DATA> , std::wstring> > fakeData;
static std::size_t openHandles;
static HANDLE FindFirst(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) {
BOOST_REQUIRE(!fakeData.empty());
BOOST_REQUIRE_EQUAL(lpFileName, fakeData.front().second);
openHandles++;
BOOST_REQUIRE_EQUAL(openHandles, 1);
if (fakeData.front().first.empty()) {
openHandles--;
SetLastError(ERROR_PATH_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
*lpFindFileData = fakeData.front().first.front();
fakeData.front().first.pop_front();
return reinterpret_cast<HANDLE>(42);
};
static BOOL FindNext(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) {
BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
if (fakeData.front().first.empty()) {
SetLastError(ERROR_NO_MORE_FILES);
return 0;
}
*lpFindFileData = fakeData.front().first.front();
fakeData.front().first.pop_front();
return 1;
};
static BOOL Close(HANDLE hFindFile) {
BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
openHandles--;
BOOST_REQUIRE_EQUAL(openHandles, 0);
fakeData.pop_front();
return 1;
};
};
std::deque<std::pair<std::deque<WIN32_FIND_DATA> , std::wstring> > RecursiveFakeFindXFileFunctions::fakeData;
std::size_t RecursiveFakeFindXFileFunctions::openHandles;
struct RecursiveDirectoryFixture
{
RecursiveDirectoryFixture() {
WIN32_FIND_DATAW tempData;
ZeroMemory(&tempData, sizeof(tempData));
std::deque<WIN32_FIND_DATAW> dequeData;
wcscpy_s(tempData.cFileName, L".");
wcscpy_s(tempData.cAlternateFileName, L".");
tempData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
GetSystemTimeAsFileTime(&tempData.ftCreationTime);
tempData.ftLastWriteTime = tempData.ftCreationTime;
tempData.ftLastAccessTime = tempData.ftCreationTime;
dequeData.push_back(tempData);
wcscpy_s(tempData.cFileName, L"..");
wcscpy_s(tempData.cAlternateFileName, L"..");
dequeData.push_back(tempData);
wcscpy_s(tempData.cFileName, L"MySubDirectory");
wcscpy_s(tempData.cAlternateFileName, L"MYSUBD~1");
dequeData.push_back(tempData);
wcscpy_s(tempData.cFileName, L"MyFile.txt");
wcscpy_s(tempData.cAlternateFileName, L"MYFILE.TXT");
tempData.nFileSizeLow = 500;
tempData.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
dequeData.push_back(tempData);
RecursiveFakeFindXFileFunctions::fakeData.push_back
(std::make_pair(dequeData, L"C:\\Windows\\*"));
dequeData.clear();
wcscpy_s(tempData.cFileName, L".");
wcscpy_s(tempData.cAlternateFileName, L".");
tempData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
GetSystemTimeAsFileTime(&tempData.ftCreationTime);
tempData.ftLastWriteTime = tempData.ftCreationTime;
tempData.ftLastAccessTime = tempData.ftCreationTime;
dequeData.push_back(tempData);
wcscpy_s(tempData.cFileName, L"..");
wcscpy_s(tempData.cAlternateFileName, L"..");
dequeData.push_back(tempData);
wcscpy_s(tempData.cFileName, L"MyFile2.txt");
wcscpy_s(tempData.cAlternateFileName, L"NYFILE2.TXT");
tempData.nFileSizeLow = 1024;
tempData.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
dequeData.push_back(tempData);
RecursiveFakeFindXFileFunctions::fakeData.push_back
(std::make_pair(dequeData, L"C:\\Windows\\MySubDirectory\\*"));
};
~RecursiveDirectoryFixture() {
RecursiveFakeFindXFileFunctions::fakeData.clear();
};
};
BOOST_AUTO_TEST_SUITE( RecursiveDirectoryIteratorTests )
BOOST_AUTO_TEST_CASE( BasicEnumerationTxt )
{
RecursiveDirectoryFixture DataFixture;
typedef DirectoryIterator<AllResults
,BasicRecursiveEnumeration<RecursiveFakeFindXFileFunctions> > testType;
testType begin(L"C:\\Windows\\*.txt");
testType end;
BOOST_CHECK(begin->IsFile());
BOOST_CHECK_EQUAL(begin->GetSize(), 1024);
BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows\\MySubDirectory");
BOOST_CHECK_EQUAL(begin->GetFileName(), L"MyFile2.txt");
BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MySubDirectory\\MyFile2.txt");
BOOST_CHECK(begin != end);
begin++;
BOOST_CHECK(begin->IsFile());
BOOST_CHECK_EQUAL(begin->GetSize(), 500);
BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows");
BOOST_CHECK_EQUAL(begin->GetFileName(), L"MyFile.txt");
BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MyFile.txt");
BOOST_CHECK(begin != end);
begin++;
BOOST_CHECK(begin == end);
}
BOOST_AUTO_TEST_CASE( BasicEnumerationAll )
{
RecursiveDirectoryFixture DataFixture;
typedef DirectoryIterator<AllResults
,BasicRecursiveEnumeration<RecursiveFakeFindXFileFunctions> > testType;
testType begin(L"C:\\Windows\\*");
testType end;
BOOST_CHECK(begin->IsDirectory());
BOOST_CHECK_EQUAL(begin->GetSize(), 0);
BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows");
BOOST_CHECK_EQUAL(begin->GetFileName(), L"MySubDirectory");
BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MySubDirectory");
BOOST_CHECK(begin != end);
begin++;
BOOST_CHECK(begin->IsFile());
BOOST_CHECK_EQUAL(begin->GetSize(), 1024);
BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows\\MySubDirectory");
BOOST_CHECK_EQUAL(begin->GetFileName(), L"MyFile2.txt");
BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MySubDirectory\\MyFile2.txt");
BOOST_CHECK(begin != end);
begin++;
BOOST_CHECK(begin->IsFile());
BOOST_CHECK_EQUAL(begin->GetSize(), 500);
BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows");
BOOST_CHECK_EQUAL(begin->GetFileName(), L"MyFile.txt");
BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MyFile.txt");
BOOST_CHECK(begin != end);
begin++;
BOOST_CHECK(begin == end);
}
BOOST_AUTO_TEST_CASE( RecursionOrderMaintained )
{
WIN32_FIND_DATAW tempData;
ZeroMemory(&tempData, sizeof(tempData));
std::deque<WIN32_FIND_DATAW> dequeData;
wcscpy_s(tempData.cFileName, L".");
wcscpy_s(tempData.cAlternateFileName, L".");
tempData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
GetSystemTimeAsFileTime(&tempData.ftCreationTime);
tempData.ftLastWriteTime = tempData.ftCreationTime;
tempData.ftLastAccessTime = tempData.ftCreationTime;
dequeData.push_back(tempData);
wcscpy_s(tempData.cFileName, L"..");
wcscpy_s(tempData.cAlternateFileName, L"..");
dequeData.push_back(tempData);
wcscpy_s(tempData.cFileName, L"MySubDirectory");
wcscpy_s(tempData.cAlternateFileName, L"MYSUBD~1");
dequeData.push_back(tempData);
wcscpy_s(tempData.cFileName, L"MyFile.txt");
wcscpy_s(tempData.cAlternateFileName, L"MYFILE.TXT");
tempData.nFileSizeLow = 500;
tempData.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
dequeData.push_back(tempData);
wcscpy_s(tempData.cFileName, L"Zach");
wcscpy_s(tempData.cAlternateFileName, L"ZACH");
tempData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
tempData.nFileSizeLow = 0;
dequeData.push_back(tempData);
RecursiveFakeFindXFileFunctions::fakeData.push_back
(std::make_pair(dequeData, L"C:\\Windows\\*"));
dequeData.clear();
wcscpy_s(tempData.cFileName, L".");
wcscpy_s(tempData.cAlternateFileName, L".");
tempData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
GetSystemTimeAsFileTime(&tempData.ftCreationTime);
tempData.ftLastWriteTime = tempData.ftCreationTime;
tempData.ftLastAccessTime = tempData.ftCreationTime;
dequeData.push_back(tempData);
wcscpy_s(tempData.cFileName, L"..");
wcscpy_s(tempData.cAlternateFileName, L"..");
dequeData.push_back(tempData);
wcscpy_s(tempData.cFileName, L"MyFile2.txt");
wcscpy_s(tempData.cAlternateFileName, L"NYFILE2.TXT");
tempData.nFileSizeLow = 1024;
tempData.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
dequeData.push_back(tempData);
RecursiveFakeFindXFileFunctions::fakeData.push_back
(std::make_pair(dequeData, L"C:\\Windows\\MySubDirectory\\*"));
dequeData.clear();
wcscpy_s(tempData.cFileName, L".");
wcscpy_s(tempData.cAlternateFileName, L".");
tempData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
GetSystemTimeAsFileTime(&tempData.ftCreationTime);
tempData.ftLastWriteTime = tempData.ftCreationTime;
tempData.ftLastAccessTime = tempData.ftCreationTime;
dequeData.push_back(tempData);
wcscpy_s(tempData.cFileName, L"..");
wcscpy_s(tempData.cAlternateFileName, L"..");
dequeData.push_back(tempData);
wcscpy_s(tempData.cFileName, L"ZachFile.txt");
wcscpy_s(tempData.cAlternateFileName, L"ZACHFILE.TXT");
tempData.nFileSizeLow = 1024;
tempData.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
dequeData.push_back(tempData);
RecursiveFakeFindXFileFunctions::fakeData.push_back
(std::make_pair(dequeData, L"C:\\Windows\\Zach\\*"));
typedef DirectoryIterator<AllResults
,BasicRecursiveEnumeration<RecursiveFakeFindXFileFunctions> > testType;
testType begin(L"C:\\Windows\\*");
testType end;
BOOST_CHECK(begin->IsDirectory());
BOOST_CHECK_EQUAL(begin->GetSize(), 0);
BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows");
BOOST_CHECK_EQUAL(begin->GetFileName(), L"MySubDirectory");
BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MySubDirectory");
BOOST_CHECK(begin != end);
begin++;
BOOST_CHECK(begin->IsFile());
BOOST_CHECK_EQUAL(begin->GetSize(), 1024);
BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows\\MySubDirectory");
BOOST_CHECK_EQUAL(begin->GetFileName(), L"MyFile2.txt");
BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MySubDirectory\\MyFile2.txt");
BOOST_CHECK(begin != end);
begin++;
BOOST_CHECK(begin->IsFile());
BOOST_CHECK_EQUAL(begin->GetSize(), 500);
BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows");
BOOST_CHECK_EQUAL(begin->GetFileName(), L"MyFile.txt");
BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MyFile.txt");
BOOST_CHECK(begin != end);
begin++;
BOOST_CHECK(begin->IsDirectory());
BOOST_CHECK_EQUAL(begin->GetSize(), 0);
BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows");
BOOST_CHECK_EQUAL(begin->GetFileName(), L"Zach");
BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\Zach");
BOOST_CHECK(begin != end);
begin++;
BOOST_CHECK(begin->IsFile());
BOOST_CHECK_EQUAL(begin->GetSize(), 1024);
BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows\\Zach");
BOOST_CHECK_EQUAL(begin->GetFileName(), L"ZachFile.txt");
BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\Zach\\ZachFile.txt");
BOOST_CHECK(begin != end);
begin++;
BOOST_CHECK(begin == end);
}
BOOST_AUTO_TEST_CASE( Exceptions )
{
typedef DirectoryIterator<AllResults,BasicRecursiveEnumeration<ErroneousFindXFileFunctionFirst> >
firstFailType;
BOOST_CHECK_THROW(firstFailType(L"C:\\Windows\\*"), WindowsAPI::ErrorAccessDeniedException);
typedef DirectoryIterator<AllResults,BasicRecursiveEnumeration<ErroneousFindXFileFunctionNext> >
nextFailType;
BOOST_CHECK_THROW(nextFailType(L"C:\\Windows\\*"), WindowsAPI::ErrorInvalidParameterException);
}
BOOST_AUTO_TEST_SUITE_END()
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <string>
#include <iterator>
#include <exception>
#ifndef DIR_ITERATOR_H_INC
#define DIR_ITERATOR_H_INC
class dir_iterator
#if (!defined(_MSC_VER)) || (_MSC_VER > 1200)
: public std::iterator<std::input_iterator_tag,
std::string,
int,
std::string *,
std::string &>
#endif
{
mutable HANDLE it;
std::string mask;
std::string path;
WIN32_FIND_DATA data;
bool done;
DWORD require;
DWORD prohibit;
public:
WIN32_FIND_DATA operator*() {
return data;
}
dir_iterator(dir_iterator const &other) :
it(other.it),
mask(other.mask),
path(other.path),
data(other.data),
done(other.done),
require(other.require),
prohibit(other.prohibit)
{
// Transfer the handle instead of just copying it.
other.it=INVALID_HANDLE_VALUE;
}
dir_iterator(std::string const &s,
DWORD must = 0,
DWORD cant = FILE_ATTRIBUTE_DIRECTORY)
: mask(s),
require(must),
prohibit(cant & ~must),
done(false),
it(INVALID_HANDLE_VALUE) // To fix bug spotted by Billy ONeal.
{
int pos;
if (std::string::npos != (pos=mask.find_last_of("\\/")))
path = std::string(mask, 0, pos+1);
it = FindFirstFile(mask.c_str(), &data);
if (it == INVALID_HANDLE_VALUE)
throw std::invalid_argument("Directory Inaccessible");
while (!(((data.dwFileAttributes & require) == require) &&
((data.dwFileAttributes & prohibit) == 0)))
{
if (done = (FindNextFile(it, &data)==0))
break;
}
}
dir_iterator() : done(true) {}
dir_iterator &operator++() {
do {
if (done = (FindNextFile(it, &data)==0))
break;
} while (!(((data.dwFileAttributes & require) == require) &&
(data.dwFileAttributes & prohibit) == 0));
return *this;
}
bool operator!=(dir_iterator const &other) {
return done != other.done;
}
bool operator==(dir_iterator const &other) {
return done == other.done;
}
~dir_iterator() {
// The rest of the bug fix -- only close handle if it's open.
if (it!=INVALID_HANDLE_VALUE)
FindClose(it);
}
};
#endif
#include "dir_iterator.h"
#include <iostream>
#include <algorithm>
namespace std {
std::ostream &operator<<(std::ostream &os, WIN32_FIND_DATA const &d) {
return os << d.cFileName;
}
}
int main() {
std::copy(dir_iterator("*"), dir_iterator(),
std::ostream_iterator<WIN32_FIND_DATA>(std::cout, "\n"));
std::cout << "\nDirectories:\n";
std::copy(dir_iterator("*", FILE_ATTRIBUTE_DIRECTORY), dir_iterator(),
std::ostream_iterator<WIN32_FIND_DATA>(std::cout, "\n"));
return 0;
}
namespace fs = boost::filesystem;
size_t nTotal = 0;
try
{
const fs::path pth("c:\\temp");
//default construction yields past-the-end
fs::recursive_directory_iterator itEnd;
for (fs::recursive_directory_iterator it(pth); it != itEnd; ++it)
{
const fs::directory_entry& rEntry = *it;
if (fs::is_regular_file(rEntry))
{
nTotal += fs::file_size(rEntry);
}
}
}
catch (const fs::filesystem_error& re)
{
//when directoy or file is not found
}