Files
nana/include/nana/filesystem/file_iterator.hpp
2015-12-16 01:21:44 +08:00

255 lines
5.2 KiB
C++

/*
* A File Iterator Implementation
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: filesystem/file_iterator.hpp
* @description:
* file_iterator is a toolkit for applying each file and directory in a
* specified path.
*/
#ifndef NANA_FILESYSTEM_FILE_ITERATOR_HPP
#define NANA_FILESYSTEM_FILE_ITERATOR_HPP
#include <iterator>
#include <memory>
#include <nana/deploy.hpp>
#ifdef NANA_WINDOWS
#include <windows.h>
typedef HANDLE find_handle_t;
#elif defined(NANA_LINUX) || defined(NANA_MACOS)
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
typedef DIR* find_handle_t;
#endif
namespace nana
{
namespace filesystem
{
struct fileinfo
{
fileinfo();
#ifdef NANA_WINDOWS
fileinfo(const WIN32_FIND_DATA& wfd);
#elif defined(NANA_POSIX)
fileinfo(const std::string& filename, const struct stat &);
#endif
::std::string name;
unsigned long size;
bool directory;
};
template<typename FileInfo>
class basic_file_iterator
:public std::iterator<std::input_iterator_tag, FileInfo>
{
public:
typedef FileInfo value_type;
basic_file_iterator():end_(true), handle_(nullptr){}
basic_file_iterator(const std::string& file_path)
:end_(false), handle_(nullptr)
{
_m_prepare(file_path);
}
const value_type&
operator*() const { return value_; }
const value_type*
operator->() const { return &(operator*()); }
basic_file_iterator& operator++()
{ _m_read(); return *this; }
basic_file_iterator operator++(int)
{
basic_file_iterator tmp = *this;
_m_read();
return tmp;
}
bool equal(const basic_file_iterator& x) const
{
if(end_ && (end_ == x.end_)) return true;
return (value_.name == x.value_.name);
}
private:
template<typename Char>
static bool _m_ignore(const Char * p)
{
while(*p == '.')
++p;
return (*p == 0);
}
void _m_prepare(const std::string& file_path)
{
#if defined(NANA_WINDOWS)
auto pat = utf8_cast(file_path);
DWORD attr = ::GetFileAttributes(pat.data());
if((attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY))
pat += L"\\*";
::HANDLE handle = ::FindFirstFile(pat.data(), &wfd_);
if(handle == INVALID_HANDLE_VALUE)
{
end_ = true;
return;
}
while(_m_ignore(wfd_.cFileName))
{
if(::FindNextFile(handle, &wfd_) == 0)
{
end_ = true;
::FindClose(handle);
return;
}
}
value_ = value_type(wfd_);
#elif defined(NANA_LINUX) || defined(NANA_MACOS)
path_ = file_path;
if(path_.size() && path_.back() != '/')
path_ += '/';
auto handle = opendir(path_.c_str());
end_ = true;
if(handle)
{
struct dirent * dnt = readdir(handle);
if(dnt)
{
while(_m_ignore(dnt->d_name))
{
dnt = readdir(handle);
if(dnt == 0)
{
closedir(handle);
return;
}
}
struct stat fst;
if(stat((path_ + dnt->d_name).c_str(), &fst) == 0)
{
value_ = value_type(dnt->d_name, fst);
}
else
{
value_.name = nana::charset(dnt->d_name);
value_.size = 0;
value_.directory = false;
}
end_ = false;
}
}
#endif
if(false == end_)
{
find_ptr_ = std::shared_ptr<find_handle_t>(new find_handle_t(handle), inner_handle_deleter());
handle_ = handle;
}
}
void _m_read()
{
if(handle_)
{
#if defined(NANA_WINDOWS)
if(::FindNextFile(handle_, &wfd_) != 0)
{
while(_m_ignore(wfd_.cFileName))
{
if(::FindNextFile(handle_, &wfd_) == 0)
{
end_ = true;
return;
}
}
value_ = value_type(wfd_);
}
else
end_ = true;
#elif defined(NANA_LINUX) || defined(NANA_MACOS)
struct dirent * dnt = readdir(handle_);
if(dnt)
{
while(_m_ignore(dnt->d_name))
{
dnt = readdir(handle_);
if(dnt == 0)
{
end_ = true;
return;
}
}
struct stat fst;
if(stat((path_ + "/" + dnt->d_name).c_str(), &fst) == 0)
value_ = value_type(nana::charset(dnt->d_name), fst);
else
value_.name = nana::charset(dnt->d_name);
}
else
end_ = true;
#endif
}
}
private:
struct inner_handle_deleter
{
void operator()(find_handle_t * handle)
{
if(handle && *handle)
{
#if defined(NANA_WINDOWS)
::FindClose(*handle);
#elif defined(NANA_LINUX) || defined(NANA_MACOS)
::closedir(*handle);
#endif
}
delete handle;
}
};
private:
bool end_;
#if defined(NANA_WINDOWS)
WIN32_FIND_DATA wfd_;
#else
std::string path_;
#endif
std::shared_ptr<find_handle_t> find_ptr_;
find_handle_t handle_;
value_type value_;
};
template<typename Value_Type>
inline bool operator==(const basic_file_iterator<Value_Type> & x, const basic_file_iterator<Value_Type> & y)
{
return x.equal(y);
}
template<typename Value_Type>
inline bool operator!=(const basic_file_iterator<Value_Type> & x, const basic_file_iterator<Value_Type> & y)
{
return !x.equal(y);
}
typedef basic_file_iterator<fileinfo> file_iterator;
}//end namespace filesystem
}//end namespace nana
#endif