diff options
Diffstat (limited to 'ml/dlib/dlib/dir_nav')
-rw-r--r-- | ml/dlib/dlib/dir_nav/dir_nav_extensions.cpp | 121 | ||||
-rw-r--r-- | ml/dlib/dlib/dir_nav/dir_nav_extensions.h | 172 | ||||
-rw-r--r-- | ml/dlib/dlib/dir_nav/dir_nav_extensions_abstract.h | 203 | ||||
-rw-r--r-- | ml/dlib/dlib/dir_nav/dir_nav_kernel_1.cpp | 258 | ||||
-rw-r--r-- | ml/dlib/dlib/dir_nav/dir_nav_kernel_1.h | 634 | ||||
-rw-r--r-- | ml/dlib/dlib/dir_nav/dir_nav_kernel_2.cpp | 254 | ||||
-rw-r--r-- | ml/dlib/dlib/dir_nav/dir_nav_kernel_2.h | 659 | ||||
-rw-r--r-- | ml/dlib/dlib/dir_nav/dir_nav_kernel_abstract.h | 515 | ||||
-rw-r--r-- | ml/dlib/dlib/dir_nav/posix.h | 6 | ||||
-rw-r--r-- | ml/dlib/dlib/dir_nav/windows.h | 6 |
10 files changed, 2828 insertions, 0 deletions
diff --git a/ml/dlib/dlib/dir_nav/dir_nav_extensions.cpp b/ml/dlib/dlib/dir_nav/dir_nav_extensions.cpp new file mode 100644 index 000000000..db05e4cc4 --- /dev/null +++ b/ml/dlib/dlib/dir_nav/dir_nav_extensions.cpp @@ -0,0 +1,121 @@ +// Copyright (C) 2009 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_EXTENSIONs_CPP_ +#define DLIB_DIR_NAV_EXTENSIONs_CPP_ + +#include "dir_nav_extensions.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + namespace implementation_details + { + void get_all_sub_dirs ( + const directory& top_of_tree, + unsigned long max_depth, + std::vector<directory>& result, + std::vector<directory>& temp + ) + { + if (max_depth > 0) + { + top_of_tree.get_dirs(temp); + const unsigned long start = result.size(); + result.insert(result.end(), temp.begin(), temp.end()); + const unsigned long end = start + temp.size(); + + for (unsigned long i = start; i < end; ++i) + { + get_all_sub_dirs(result[i], max_depth-1, result, temp); + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + bool file_exists ( + const std::string& filename + ) + { + try + { + dlib::file temp(filename); + return true; + } + catch (file::file_not_found&) + { + return false; + } + } + +// ---------------------------------------------------------------------------------------- + + directory get_parent_directory ( + const directory& dir + ) + { + return dir.get_parent(); + } + +// ---------------------------------------------------------------------------------------- + + directory get_parent_directory ( + const file& f + ) + { + if (f.full_name().size() == 0) + return directory(); + + std::string::size_type pos = f.full_name().find_last_of("\\/"); + + if (pos == std::string::npos) + return directory(); + + return directory(f.full_name().substr(0,pos)); + } + +// ---------------------------------------------------------------------------------------- + + std::string select_oldest_file ( + const std::string& filename1, + const std::string& filename2 + ) + { + file f1, f2; + try{f1 = file(filename1);} catch(file::file_not_found&) { return filename1; } + try{f2 = file(filename2);} catch(file::file_not_found&) { return filename2; } + + if (f1.last_modified() < f2.last_modified()) + return filename1; + else + return filename2; + } + +// ---------------------------------------------------------------------------------------- + + std::string select_newest_file ( + const std::string& filename1, + const std::string& filename2 + ) + { + file f1, f2; + try{f1 = file(filename1);} catch(file::file_not_found&) { return filename2; } + try{f2 = file(filename2);} catch(file::file_not_found&) { return filename1; } + + if (f1.last_modified() > f2.last_modified()) + return filename1; + else + return filename2; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DIR_NAV_EXTENSIONs_CPP_ + + + diff --git a/ml/dlib/dlib/dir_nav/dir_nav_extensions.h b/ml/dlib/dlib/dir_nav/dir_nav_extensions.h new file mode 100644 index 000000000..93dde1159 --- /dev/null +++ b/ml/dlib/dlib/dir_nav/dir_nav_extensions.h @@ -0,0 +1,172 @@ +// Copyright (C) 2009 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_EXTENSIONs_H_ +#define DLIB_DIR_NAV_EXTENSIONs_H_ + +#include <string> +#include <vector> +#include <algorithm> +#include "dir_nav_extensions_abstract.h" +#include "../dir_nav.h" +#include "../string.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + bool file_exists ( + const std::string& filename + ); + +// ---------------------------------------------------------------------------------------- + + namespace implementation_details + { + void get_all_sub_dirs ( + const directory& top_of_tree, + unsigned long max_depth, + std::vector<directory>& result, + std::vector<directory>& temp + ); + } + +// ---------------------------------------------------------------------------------------- + + template <typename T> + const std::vector<file> get_files_in_directory_tree ( + const directory& top_of_tree, + const T& add_file, + unsigned long max_depth = 30 + ) + { + std::vector<file> result, temp; + std::vector<directory> dirs, dirs_temp; + dirs.push_back(top_of_tree); + + // get all the directories in the tree first + implementation_details::get_all_sub_dirs(top_of_tree, max_depth, dirs, dirs_temp); + + // now just loop over all the directories and pick out the files we want to keep + for (unsigned long d = 0; d < dirs.size(); ++d) + { + dirs[d].get_files(temp); + + // pick out the members of temp that we should keep + for (unsigned long i = 0; i < temp.size(); ++i) + { + if (add_file(temp[i])) + result.push_back(temp[i]); + } + } + + return result; + } + +// ---------------------------------------------------------------------------------------- + + class match_ending + { + + public: + match_ending ( + const std::string& ending_ + ) : ending(ending_) {} + + bool operator() ( + const file& f + ) const + { + // if the ending is bigger than f's name then it obviously doesn't match + if (ending.size() > f.name().size()) + return false; + + // now check if the actual characters that make up the end of the file name + // matches what is in ending. + return std::equal(ending.begin(), ending.end(), f.name().end()-ending.size()); + } + + private: + std::string ending; + }; + +// ---------------------------------------------------------------------------------------- + + class match_endings + { + + public: + match_endings ( + const std::string& endings_ + ) + { + const std::vector<std::string>& s = split(endings_); + for (unsigned long i = 0; i < s.size(); ++i) + { + endings.push_back(match_ending(s[i])); + } + } + + bool operator() ( + const file& f + ) const + { + for (unsigned long i = 0; i < endings.size(); ++i) + { + if (endings[i](f)) + return true; + } + + return false; + } + + private: + std::vector<match_ending> endings; + }; + +// ---------------------------------------------------------------------------------------- + + class match_all + { + public: + bool operator() ( + const file& + ) const { return true; } + }; + +// ---------------------------------------------------------------------------------------- + + directory get_parent_directory ( + const directory& dir + ); + +// ---------------------------------------------------------------------------------------- + + directory get_parent_directory ( + const file& f + ); + +// ---------------------------------------------------------------------------------------- + + std::string select_oldest_file ( + const std::string& filename1, + const std::string& filename2 + ); + +// ---------------------------------------------------------------------------------------- + + std::string select_newest_file ( + const std::string& filename1, + const std::string& filename2 + ); + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "dir_nav_extensions.cpp" +#endif + +#endif // DLIB_DIR_NAV_EXTENSIONs_H_ + diff --git a/ml/dlib/dlib/dir_nav/dir_nav_extensions_abstract.h b/ml/dlib/dlib/dir_nav/dir_nav_extensions_abstract.h new file mode 100644 index 000000000..4aa6cc4f2 --- /dev/null +++ b/ml/dlib/dlib/dir_nav/dir_nav_extensions_abstract.h @@ -0,0 +1,203 @@ +// Copyright (C) 2009 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DIR_NAV_EXTENSIONs_ABSTRACT_ +#ifdef DLIB_DIR_NAV_EXTENSIONs_ABSTRACT_ + +#include <string> +#include <vector> +#include "dir_nav_kernel_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + bool file_exists ( + const std::string& filename + ); + /*! + ensures + - if (a file with the given filename exists) then + - returns true + - else + - returns false + !*/ + +// ---------------------------------------------------------------------------------------- + + template <typename T> + const std::vector<file> get_files_in_directory_tree ( + const directory& top_of_tree, + const T& add_file, + unsigned long max_depth = 30 + ); + /*! + requires + - add_file must be a function object with the following prototype: + bool add_file (file f); + ensures + - performs a recursive search through the directory top_of_tree and all + its sub-directories (up to the given max depth). All files in these + directories are examined by passing them to add_file() and if it + returns true then they will be included in the returned std::vector<file> + object. + - Note that a max_depth of 0 means that only the files in the directory + top_of_tree will be considered. A depth of 1 means that only files in + top_of_tree and its immediate sub-directories will be considered. And + so on... + !*/ + +// ---------------------------------------------------------------------------------------- + + class match_ending + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple function object that can be used with the + above get_files_in_directory_tree() function. This object + just looks for files with a certain ending. + !*/ + + public: + match_ending ( + const std::string& ending + ); + /*! + ensures + - this object will be a function that checks if a file has a + name that ends with the given ending string. + !*/ + + bool operator() ( + const file& f + ) const; + /*! + ensures + - if (the file f has a name that ends with the ending string given + to this object's constructor) then + - returns true + - else + - returns false + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class match_endings + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple function object that can be used with the + above get_files_in_directory_tree() function. This object + allows you to look for files with a number of different + endings. + !*/ + + public: + match_endings ( + const std::string& ending_list + ); + /*! + ensures + - ending_list is interpreted as a whitespace separated list + of file endings. + - this object will be a function that checks if a file has a + name that ends with one of the strings in ending_list. + !*/ + + bool operator() ( + const file& f + ) const; + /*! + ensures + - if (the file f has a name that ends with one of the ending strings + given to this object's constructor) then + - returns true + - else + - returns false + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class match_all + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple function object that can be used with the + above get_files_in_directory_tree() function. This object + matches all files. + !*/ + + public: + bool operator() ( + const file& f + ) const; + /*! + ensures + - returns true + (i.e. this function doesn't do anything. It just says it + matches all files no matter what) + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + directory get_parent_directory ( + const directory& dir + ); + /*! + ensures + - returns the parent directory of dir. In particular, this + function returns the value of dir.get_parent() + !*/ + +// ---------------------------------------------------------------------------------------- + + directory get_parent_directory ( + const file& f + ); + /*! + ensures + - if (f.full_name() != "") then + - returns the directory which contains the given file + - else + - returns a default initialized directory (i.e. directory()) + !*/ + +// ---------------------------------------------------------------------------------------- + + std::string select_oldest_file ( + const std::string& filename1, + const std::string& filename2 + ); + /*! + ensures + - Checks the last modification times of the two given files and returns the + filename of the oldest file, i.e., the file that has gone longest since being + modified. Ties are broken arbitrarily. + - For the purpose of comparison, a file that doesn't exist is presumed to have + a last modification time of -infinity (i.e. very far in the past). + !*/ + +// ---------------------------------------------------------------------------------------- + + std::string select_newest_file ( + const std::string& filename1, + const std::string& filename2 + ); + /*! + ensures + - Checks the last modification times of the two given files and returns the + filename that was most recently modified. Ties are broken arbitrarily. + - For the purpose of comparison, a file that doesn't exist is presumed to have + a last modification time of -infinity (i.e. very far in the past). + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DIR_NAV_EXTENSIONs_ABSTRACT_ + + diff --git a/ml/dlib/dlib/dir_nav/dir_nav_kernel_1.cpp b/ml/dlib/dlib/dir_nav/dir_nav_kernel_1.cpp new file mode 100644 index 000000000..9891d5dff --- /dev/null +++ b/ml/dlib/dlib/dir_nav/dir_nav_kernel_1.cpp @@ -0,0 +1,258 @@ +// Copyright (C) 2003 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_KERNEL_1_CPp_ +#define DLIB_DIR_NAV_KERNEL_1_CPp_ +#include "../platform.h" + +#ifdef WIN32 + +#include "dir_nav_kernel_1.h" +#include "../string.h" + + +#ifdef __BORLANDC__ +// Apparently the borland compiler doesn't define this. +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // file object implementation +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void file:: + init ( + const std::string& name + ) + { + using namespace std; + + + char buf[3000]; + char* str; + if (GetFullPathNameA(name.c_str(),sizeof(buf),buf,&str) == 0) + { + // the file was not found + throw file_not_found("Unable to find file " + name); + } + state.full_name = buf; + + + string::size_type pos = state.full_name.find_last_of(directory::get_separator()); + if (pos == string::npos) + { + // no valid full path has no separator characters. + throw file_not_found("Unable to find file " + name); + } + state.name = state.full_name.substr(pos+1); + + + // now find the size of this file + WIN32_FIND_DATAA data; + HANDLE ffind = FindFirstFileA(state.full_name.c_str(), &data); + if (ffind == INVALID_HANDLE_VALUE || + (data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0) + { + throw file_not_found("Unable to find file " + name); + } + else + { + uint64 temp = data.nFileSizeHigh; + temp <<= 32; + temp |= data.nFileSizeLow; + state.file_size = temp; + FindClose(ffind); + + ULARGE_INTEGER ull; + ull.LowPart = data.ftLastWriteTime.dwLowDateTime; + ull.HighPart = data.ftLastWriteTime.dwHighDateTime; + std::chrono::nanoseconds epoch(100 * (ull.QuadPart - 116444736000000000)); + state.last_modified = std::chrono::time_point<std::chrono::system_clock>(std::chrono::duration_cast<std::chrono::system_clock::duration>(epoch)); + } + + } + +// ---------------------------------------------------------------------------------------- + + bool file:: + operator == ( + const file& rhs + ) const + { + using namespace std; + + if (state.full_name.size() != rhs.state.full_name.size()) + return false; + + // compare the strings but ignore the case because file names + // are not case sensitive on windows + return tolower(state.full_name) == tolower(rhs.state.full_name); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // directory object implementation +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void directory:: + init ( + const std::string& name + ) + { + using namespace std; + + + char buf[3000]; + char* str; + if (GetFullPathNameA(name.c_str(),sizeof(buf),buf,&str) == 0) + { + // the directory was not found + throw dir_not_found("Unable to find directory " + name); + } + state.full_name = buf; + + + const char sep = get_separator(); + if (is_root_path(state.full_name) == false) + { + // ensure that thre is not a trialing separator + if (state.full_name[state.full_name.size()-1] == sep) + state.full_name.erase(state.full_name.size()-1); + + // pick out the directory name + string::size_type pos = state.full_name.find_last_of(sep); + state.name = state.full_name.substr(pos+1); + } + else + { + // ensure that there is a trailing separator + if (state.full_name[state.full_name.size()-1] != sep) + state.full_name += sep; + } + + + // now check that this is actually a valid directory + DWORD attribs = GetFileAttributesA(state.full_name.c_str()); + if (attribs == INVALID_FILE_ATTRIBUTES || + (attribs&FILE_ATTRIBUTE_DIRECTORY) == 0) + { + // the directory was not found + throw dir_not_found("Unable to find directory " + name); + } + + } + +// ---------------------------------------------------------------------------------------- + + char directory:: + get_separator ( + ) + { + return '\\'; + } + +// ---------------------------------------------------------------------------------------- + + bool directory:: + operator == ( + const directory& rhs + ) const + { + using namespace std; + + if (state.full_name.size() != rhs.state.full_name.size()) + return false; + + // compare the strings but ignore the case because file names + // are not case sensitive on windows + return tolower(state.full_name) == tolower(rhs.state.full_name); + } + +// ---------------------------------------------------------------------------------------- + + const directory directory:: + get_parent ( + ) const + { + using namespace std; + // if *this is the root then just return *this + if (is_root()) + { + return *this; + } + else + { + directory temp; + + const char sep = get_separator(); + + string::size_type pos = state.full_name.find_last_of(sep); + temp.state.full_name = state.full_name.substr(0,pos); + + if ( is_root_path(temp.state.full_name)) + { + temp.state.full_name += sep; + } + else + { + pos = temp.state.full_name.find_last_of(sep); + if (pos != string::npos) + { + temp.state.name = temp.state.full_name.substr(pos+1); + } + else + { + temp.state.full_name += sep; + } + } + return temp; + } + } + +// ---------------------------------------------------------------------------------------- + + bool directory:: + is_root_path ( + const std::string& path + ) const + { + using namespace std; + const char sep = get_separator(); + bool root_path = false; + if (path.size() > 2 && path[0] == sep && path[1] == sep) + { + // in this case this is a windows share path + string::size_type pos = path.find_first_of(sep,2); + if (pos != string::npos) + { + pos = path.find_first_of(sep,pos+1); + + if (pos == string::npos && path[path.size()-1] != sep) + root_path = true; + else if (pos == path.size()-1) + root_path = true; + } + + } + else if ( (path.size() == 2 || path.size() == 3) && path[1] == ':') + { + // if this is a valid windows path then it must be a root path + root_path = true; + } + + return root_path; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // WIN32 + +#endif // DLIB_DIR_NAV_KERNEL_1_CPp_ + diff --git a/ml/dlib/dlib/dir_nav/dir_nav_kernel_1.h b/ml/dlib/dlib/dir_nav/dir_nav_kernel_1.h new file mode 100644 index 000000000..a31f689de --- /dev/null +++ b/ml/dlib/dlib/dir_nav/dir_nav_kernel_1.h @@ -0,0 +1,634 @@ +// Copyright (C) 2003 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_KERNEl_1_ +#define DLIB_DIR_NAV_KERNEl_1_ + +#ifdef DLIB_ISO_CPP_ONLY +#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." +#endif + +#include "../platform.h" + + +#include "dir_nav_kernel_abstract.h" +#include <string> +#include "../uintn.h" +#include "../algs.h" + +#include "../windows_magic.h" +#include <windows.h> +#include <vector> +#include "../stl_checked.h" +#include "../enable_if.h" +#include "../queue.h" +#include <chrono> + +namespace dlib +{ + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // file object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class file + { + /*! + INITIAL VALUES + state.name == name() + state.full_name == full_name() + state.file_size == size() + state.last_modified == last_modified() + + CONVENTION + state.name == name() + state.full_name == full_name() + state.file_size == size() + state.last_modified == last_modified() + + !*/ + + friend class directory; + + struct data + { + uint64 file_size; + std::string name; + std::string full_name; + std::chrono::time_point<std::chrono::system_clock> last_modified; + }; + + + void init ( const std::string& name); + + public: + + struct private_constructor{}; + inline file ( + const std::string& name, + const std::string& full_name, + const uint64 file_size, + const std::chrono::time_point<std::chrono::system_clock>& last_modified, + private_constructor + ) + { + state.file_size = file_size; + state.name = name; + state.full_name = full_name; + state.last_modified = last_modified; + } + + + + + class file_not_found : public error { + public: file_not_found(const std::string& s): error(s){} + }; + + inline file ( + ) + { + state.file_size = 0; + } + + file ( + const std::string& name + ) { init(name); } + + file ( + const char* name + ) { init(name); } + + inline const std::string& name ( + ) const { return state.name; } + + inline const std::string& full_name ( + ) const { return state.full_name; } + + operator std::string ( + ) const { return full_name(); } + + inline uint64 size ( + ) const { return state.file_size; } + + inline std::chrono::time_point<std::chrono::system_clock> last_modified ( + ) const { return state.last_modified; } + + bool operator == ( + const file& rhs + ) const; + + bool operator != ( + const file& rhs + ) const { return !(*this == rhs); } + + inline bool operator < ( + const file& item + ) const { return full_name() < item.full_name(); } + + inline void swap ( + file& item + ) + { + exchange(state,item.state); + } + + private: + + data state; + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // directory object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class directory + { + /*! + INITIAL VALUES + state.name == name() + state.full_name == full_name() + + CONVENTION + state.name == name() + state.full_name == full_name() + is_root() == state.name.size() == 0 + + !*/ + + void init (const std::string& name); + + public: + + struct data + { + std::string name; + std::string full_name; + }; + + + /* + The reason we don't just make this constructor actually + private is because doing it this way avoids a bug that + sometimes occurs in visual studio 7.1. The bug has + something to do with templated friend functions + such as the get_filesystem_roots() function below if + it was declared as a friend template of this class. + */ + struct private_constructor{}; + inline directory ( + const std::string& name, + const std::string& full_name, + private_constructor + ) + { + state.name = name; + state.full_name = full_name; + } + + + class dir_not_found : public error { + public: dir_not_found(const std::string& s):error(s){} + }; + class listing_error : public error { + public: listing_error(const std::string& s):error(s){} + }; + + inline directory ( + ) + { + } + + directory ( + const std::string& name + ) { init(name); } + + directory ( + const char* name + ) { init(name); } + + + static char get_separator ( + ); + + + template < + typename queue_of_files + > + void get_files ( + queue_of_files& files + ) const; + + template < + typename queue_of_dirs + > + void get_dirs ( + queue_of_dirs& dirs + ) const; + + std::vector<file> get_files ( + ) const + { + std::vector<file> temp_vector; + get_files(temp_vector); + return temp_vector; + } + + std::vector<directory> get_dirs ( + ) const + { + std::vector<directory> temp_vector; + get_dirs(temp_vector); + return temp_vector; + } + + const directory get_parent ( + ) const; + + inline bool is_root ( + ) const { return state.name.size() == 0; } + + inline const std::string& name ( + ) const { return state.name; } + + inline const std::string& full_name ( + ) const { return state.full_name; } + + operator std::string ( + ) const { return full_name(); } + + bool operator == ( + const directory& rhs + ) const; + + bool operator != ( + const directory& rhs + ) const { return !(*this == rhs); } + + inline bool operator < ( + const directory& item + ) const { return full_name() < item.full_name(); } + + inline void swap ( + directory& item + ) + { + exchange(state,item.state); + } + + private: + + // member data + data state; + + bool is_root_path ( + const std::string& path + ) const; + /*! + ensures + - returns true if path is a root path. + Note that this function considers root paths that don't + have a trailing separator to also be valid. + !*/ + + + }; + +// ---------------------------------------------------------------------------------------- + + inline std::ostream& operator<< ( + std::ostream& out, + const directory& item + ) { out << (std::string)item; return out; } + + inline std::ostream& operator<< ( + std::ostream& out, + const file& item + ) { out << (std::string)item; return out; } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dir + > + typename disable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots ( + queue_of_dir& roots + ) + { + roots.clear(); + const DWORD mask = GetLogicalDrives(); + DWORD bit = 1; + char buf[] = "A:\\"; + + do + { + if (mask & bit) + { + directory dir("",buf,directory::private_constructor()); + roots.enqueue(dir); + } + bit <<= 1; + ++buf[0]; + } while (buf[0] != 'Z'); + } + + template < + typename queue_of_dir + > + typename enable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots ( + queue_of_dir& roots + ) + { + roots.clear(); + const DWORD mask = GetLogicalDrives(); + DWORD bit = 1; + char buf[] = "A:\\"; + + do + { + if (mask & bit) + { + directory dir("",buf,directory::private_constructor()); + roots.push_back(dir); + } + bit <<= 1; + ++buf[0]; + } while (buf[0] != 'Z'); + } + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + file& a, + file& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + directory& a, + directory& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // templated member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_files + > + typename disable_if<is_std_vector<queue_of_files>,void>::type + directory_helper_get_files ( + const directory::data& state, + queue_of_files& files + ) + { + using namespace std; + typedef directory::listing_error listing_error; + typedef file::private_constructor private_constructor; + + files.clear(); + if (state.full_name.size() == 0) + throw listing_error("This directory object currently doesn't represent any directory."); + + HANDLE ffind = INVALID_HANDLE_VALUE; + try + { + WIN32_FIND_DATAA data; + string path = state.full_name; + // ensure that the path ends with a separator + if (path[path.size()-1] != directory::get_separator()) + path += directory::get_separator(); + + ffind = FindFirstFileA((path+"*").c_str(), &data); + if (ffind == INVALID_HANDLE_VALUE) + { + throw listing_error("Unable to list the contents of " + state.full_name); + } + + + bool no_more_files = false; + do + { + if ((data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) == 0) + { + uint64 file_size = data.nFileSizeHigh; + file_size <<= 32; + file_size |= data.nFileSizeLow; + + ULARGE_INTEGER ull; + ull.LowPart = data.ftLastWriteTime.dwLowDateTime; + ull.HighPart = data.ftLastWriteTime.dwHighDateTime; + std::chrono::nanoseconds epoch(100 * (ull.QuadPart - 116444736000000000)); + auto last_modified = std::chrono::time_point<std::chrono::system_clock>(std::chrono::duration_cast<std::chrono::system_clock::duration>(epoch)); + + // this is a file so add it to the queue + file temp(data.cFileName,path+data.cFileName,file_size, last_modified, private_constructor()); + files.enqueue(temp); + } + + if (FindNextFileA(ffind,&data) == 0) + { + // an error occurred + if ( GetLastError() == ERROR_NO_MORE_FILES) + { + // there are no more files + no_more_files = true; + } + else + { + // there was an error + throw listing_error("Unable to list the contents of " + state.full_name); + } + } + } while (no_more_files == false); + + FindClose(ffind); + ffind = INVALID_HANDLE_VALUE; + } + catch (...) + { + if (ffind != INVALID_HANDLE_VALUE) + FindClose(ffind); + files.clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_files + > + typename enable_if<is_std_vector<queue_of_files>,void>::type + directory_helper_get_files ( + const directory::data& state, + queue_of_files& files + ) + { + queue<file>::kernel_2a temp_files; + directory_helper_get_files(state,temp_files); + + files.clear(); + + // copy the queue of files into the vector + temp_files.reset(); + while (temp_files.move_next()) + { + files.push_back(temp_files.element()); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_files + > + void directory:: + get_files ( + queue_of_files& files + ) const + { + // the reason for this indirection here is because it avoids a bug in + // the mingw version of gcc + directory_helper_get_files(state,files); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dirs + > + typename disable_if<is_std_vector<queue_of_dirs>,void>::type + directory_helper_get_dirs ( + const directory::data& state, + queue_of_dirs& dirs + ) + { + using namespace std; + typedef directory::listing_error listing_error; + typedef directory::private_constructor private_constructor; + + dirs.clear(); + if (state.full_name.size() == 0) + throw listing_error("This directory object currently doesn't represent any directory."); + + HANDLE dfind = INVALID_HANDLE_VALUE; + try + { + WIN32_FIND_DATAA data; + string path = state.full_name; + // ensure that the path ends with a separator + if (path[path.size()-1] != directory::get_separator()) + path += directory::get_separator(); + + dfind = FindFirstFileA((path+"*").c_str(), &data); + if (dfind == INVALID_HANDLE_VALUE) + { + throw listing_error("Unable to list the contents of " + state.full_name); + } + + + bool no_more_files = false; + do + { + string tname(data.cFileName); + if ((data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0 && + tname != "." && + tname != "..") + { + // this is a directory so add it to the queue + directory temp(tname,path+tname,private_constructor()); + dirs.enqueue(temp); + } + + if (FindNextFileA(dfind,&data) == 0) + { + // an error occurred + if ( GetLastError() == ERROR_NO_MORE_FILES) + { + // there are no more files + no_more_files = true; + } + else + { + // there was an error + throw listing_error("Unable to list the contents of " + state.full_name); + } + } + } while (no_more_files == false); + + FindClose(dfind); + dfind = INVALID_HANDLE_VALUE; + } + catch (...) + { + if (dfind != INVALID_HANDLE_VALUE) + FindClose(dfind); + dirs.clear(); + throw; + } + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dirs + > + typename enable_if<is_std_vector<queue_of_dirs>,void>::type + directory_helper_get_dirs ( + const directory::data& state, + queue_of_dirs& dirs + ) + { + queue<directory>::kernel_2a temp_dirs; + directory_helper_get_dirs(state,temp_dirs); + + dirs.clear(); + + // copy the queue of dirs into the vector + temp_dirs.reset(); + while (temp_dirs.move_next()) + { + dirs.push_back(temp_dirs.element()); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dirs + > + void directory:: + get_dirs ( + queue_of_dirs& dirs + ) const + { + // the reason for this indirection here is because it avoids a bug in + // the mingw version of gcc + directory_helper_get_dirs(state,dirs); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + +} + + +#ifdef NO_MAKEFILE +#include "dir_nav_kernel_1.cpp" +#endif + +#endif // DLIB_DIR_NAV_KERNEl_1_ + diff --git a/ml/dlib/dlib/dir_nav/dir_nav_kernel_2.cpp b/ml/dlib/dlib/dir_nav/dir_nav_kernel_2.cpp new file mode 100644 index 000000000..be97b984c --- /dev/null +++ b/ml/dlib/dlib/dir_nav/dir_nav_kernel_2.cpp @@ -0,0 +1,254 @@ +// Copyright (C) 2003 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_KERNEL_2_CPp_ +#define DLIB_DIR_NAV_KERNEL_2_CPp_ + +#include "../platform.h" + +#ifdef POSIX + + +#include "dir_nav_kernel_2.h" + + + + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // file object implementation +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void file:: + init ( + const std::string& name + ) + { + using namespace std; + + + + char buf[PATH_MAX]; + if (realpath(name.c_str(),buf) == 0) + { + // the file was not found + throw file_not_found("Unable to find file " + name); + } + state.full_name = buf; + + + string::size_type pos = state.full_name.find_last_of(directory::get_separator()); + if (pos == string::npos) + { + // no valid full path has no separtor characters. + throw file_not_found("Unable to find file " + name); + } + state.name = state.full_name.substr(pos+1); + + + // now find the size of this file + struct stat64 buffer; + if (::stat64(state.full_name.c_str(), &buffer) || + S_ISDIR(buffer.st_mode)) + { + // there was an error during the call to stat64 or + // name is actually a directory + throw file_not_found("Unable to find file " + name); + } + else + { + state.file_size = static_cast<uint64>(buffer.st_size); + + + state.last_modified = std::chrono::system_clock::from_time_t(buffer.st_mtime); +#ifdef _BSD_SOURCE + state.last_modified += std::chrono::duration_cast<std::chrono::system_clock::duration>(std::chrono::nanoseconds(buffer.st_atim.tv_nsec)); +#endif + } + + } + +// ---------------------------------------------------------------------------------------- + + bool file:: + operator == ( + const file& rhs + ) const + { + using namespace std; + if (state.full_name.size() == 0 && rhs.state.full_name.size() == 0) + return true; + + // These files might have different names but actually represent the same + // file due to the presence of symbolic links. + char buf[PATH_MAX]; + string left, right; + if (realpath(state.full_name.c_str(),buf) == 0) + return false; + left = buf; + + if (realpath(rhs.state.full_name.c_str(),buf) == 0) + return false; + right = buf; + + return (left == right); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // directory object implementation +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void directory:: + init ( + const std::string& name + ) + { + using namespace std; + + + char buf[PATH_MAX]; + if (realpath(name.c_str(),buf) == 0) + { + // the directory was not found + throw dir_not_found("Unable to find directory " + name); + } + state.full_name = buf; + + + const char sep = get_separator(); + if (is_root_path(state.full_name) == false) + { + // ensure that thre is not a trialing separator + if (state.full_name[state.full_name.size()-1] == sep) + state.full_name.erase(state.full_name.size()-1); + + // pick out the directory name + string::size_type pos = state.full_name.find_last_of(sep); + state.name = state.full_name.substr(pos+1); + } + else + { + // ensure that there is a trailing separator + if (state.full_name[state.full_name.size()-1] != sep) + state.full_name += sep; + } + + + struct stat64 buffer; + // now check that this is actually a valid directory + if (::stat64(state.full_name.c_str(),&buffer)) + { + // the directory was not found + throw dir_not_found("Unable to find directory " + name); + } + else if (S_ISDIR(buffer.st_mode) == 0) + { + // It is not a directory + throw dir_not_found("Unable to find directory " + name); + } + } + +// ---------------------------------------------------------------------------------------- + + char directory:: + get_separator ( + ) + { + return '/'; + } + +// ---------------------------------------------------------------------------------------- + + bool directory:: + operator == ( + const directory& rhs + ) const + { + using namespace std; + if (state.full_name.size() == 0 && rhs.state.full_name.size() == 0) + return true; + + // These directories might have different names but actually represent the same + // directory due to the presence of symbolic links. + char buf[PATH_MAX]; + string left, right; + if (realpath(state.full_name.c_str(),buf) == 0) + return false; + left = buf; + + if (realpath(rhs.state.full_name.c_str(),buf) == 0) + return false; + right = buf; + + return (left == right); + } + +// ---------------------------------------------------------------------------------------- + + const directory directory:: + get_parent ( + ) const + { + using namespace std; + // if *this is the root then just return *this + if (is_root()) + { + return *this; + } + else + { + directory temp; + + const char sep = get_separator(); + + string::size_type pos = state.full_name.find_last_of(sep); + temp.state.full_name = state.full_name.substr(0,pos); + + if ( is_root_path(temp.state.full_name)) + { + temp.state.full_name += sep; + } + else + { + pos = temp.state.full_name.find_last_of(sep); + if (pos != string::npos) + { + temp.state.name = temp.state.full_name.substr(pos+1); + } + else + { + temp.state.full_name += sep; + } + } + return temp; + } + } + +// ---------------------------------------------------------------------------------------- + + bool directory:: + is_root_path ( + const std::string& path + ) const + { + const char sep = get_separator(); + if (path.size() == 1 && path[0] == sep) + return true; + else + return false; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // POSIX + +#endif // DLIB_DIR_NAV_KERNEL_2_CPp_ + diff --git a/ml/dlib/dlib/dir_nav/dir_nav_kernel_2.h b/ml/dlib/dlib/dir_nav/dir_nav_kernel_2.h new file mode 100644 index 000000000..af2f3d5dc --- /dev/null +++ b/ml/dlib/dlib/dir_nav/dir_nav_kernel_2.h @@ -0,0 +1,659 @@ +// Copyright (C) 2003 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_KERNEl_2_ +#define DLIB_DIR_NAV_KERNEl_2_ + +#ifdef DLIB_ISO_CPP_ONLY +#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." +#endif + + +#include "dir_nav_kernel_abstract.h" + +#include <string> +#include "../uintn.h" +#include "../algs.h" + +#include <sys/types.h> +#include <dirent.h> +#include <libgen.h> +#include <limits.h> +#include <unistd.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdlib.h> +#include <chrono> + +#if !defined(__USE_LARGEFILE64 ) && !defined(_LARGEFILE64_SOURCE) +#define stat64 stat +#endif + +#include <vector> +#include "../stl_checked.h" +#include "../enable_if.h" +#include "../queue.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // file object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class file + { + /*! + INITIAL VALUES + state.name == name() + state.full_name == full_name() + state.file_size == size() + state.last_modified == last_modified() + + CONVENTION + state.name == name() + state.full_name == full_name() + state.file_size == size() + state.last_modified == last_modified() + + !*/ + + friend class directory; + + struct data + { + uint64 file_size; + std::string name; + std::string full_name; + std::chrono::time_point<std::chrono::system_clock> last_modified; + }; + + void init(const std::string& name); + + public: + + struct private_constructor{}; + inline file ( + const std::string& name, + const std::string& full_name, + const uint64 file_size, + const std::chrono::time_point<std::chrono::system_clock>& last_modified, + private_constructor + ) + { + state.file_size = file_size; + state.name = name; + state.full_name = full_name; + state.last_modified = last_modified; + } + + + class file_not_found : public error { + public: file_not_found(const std::string& s): error(s){} + }; + + inline file ( + ) + { + state.file_size = 0; + } + + file ( + const std::string& name + ) { init(name); } + + file ( + const char* name + ) { init(name); } + + inline const std::string& name ( + ) const { return state.name; } + + inline const std::string& full_name ( + ) const { return state.full_name; } + + inline uint64 size ( + ) const { return state.file_size; } + + inline std::chrono::time_point<std::chrono::system_clock> last_modified ( + ) const { return state.last_modified; } + + operator std::string ( + ) const { return full_name(); } + + bool operator == ( + const file& rhs + ) const; + + bool operator != ( + const file& rhs + ) const { return !(*this == rhs); } + + inline bool operator < ( + const file& item + ) const { return full_name() < item.full_name(); } + + inline void swap ( + file& item + ) + { + exchange(state,item.state); + } + + private: + + // member data + data state; + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // directory object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class directory + { + /*! + INITIAL VALUES + state.name == name() + state.full_name == full_name() + + CONVENTION + state.name == name() + state.full_name == full_name() + is_root() == state.name.size() == 0 + + !*/ + + void init(const std::string& name); + + public: + struct private_constructor{}; + inline directory ( + const std::string& name, + const std::string& full_name, + private_constructor + ) + { + state.name = name; + state.full_name = full_name; + } + + struct data + { + std::string name; + std::string full_name; + }; + + class dir_not_found : public error { + public: dir_not_found(const std::string& s):error(s){} + }; + class listing_error : public error { + public: listing_error(const std::string& s):error(s){} + }; + + inline directory ( + ) + { + } + + directory ( + const std::string& name + ) { init(name); } + + directory ( + const char* name + ) { init(name); } + + static char get_separator ( + ); + + template < + typename queue_of_files + > + void get_files ( + queue_of_files& files + ) const; + + template < + typename queue_of_dirs + > + void get_dirs ( + queue_of_dirs& dirs + ) const; + + std::vector<file> get_files ( + ) const + { + std::vector<file> temp_vector; + get_files(temp_vector); + return temp_vector; + } + + std::vector<directory> get_dirs ( + ) const + { + std::vector<directory> temp_vector; + get_dirs(temp_vector); + return temp_vector; + } + + const directory get_parent ( + ) const; + + inline bool is_root ( + ) const { return state.name.size() == 0; } + + inline const std::string& name ( + ) const { return state.name; } + + inline const std::string& full_name ( + ) const { return state.full_name; } + + operator std::string ( + ) const { return full_name(); } + + bool operator == ( + const directory& rhs + ) const; + + bool operator != ( + const directory& rhs + ) const { return !(*this == rhs); } + + inline bool operator < ( + const directory& item + ) const { return full_name() < item.full_name(); } + + inline void swap ( + directory& item + ) + { + exchange(state,item.state); + } + + private: + + // member data + data state; + + bool is_root_path ( + const std::string& path + ) const; + /*! + ensures + - returns true if path is a root path. + Note that this function considers root paths that don't + have a trailing separator to also be valid. + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + inline std::ostream& operator<< ( + std::ostream& out, + const directory& item + ) { out << (std::string)item; return out; } + + inline std::ostream& operator<< ( + std::ostream& out, + const file& item + ) { out << (std::string)item; return out; } + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + file& a, + file& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + directory& a, + directory& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // templated member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_files + > + typename disable_if<is_std_vector<queue_of_files>,void>::type + directory_helper_get_files ( + const directory::data& state, + queue_of_files& files + ) + { + using namespace std; + + files.clear(); + if (state.full_name.size() == 0) + throw directory::listing_error("This directory object currently doesn't represent any directory."); + + DIR* ffind = 0; + struct dirent* data; + struct stat64 buffer; + + try + { + string path = state.full_name; + // ensure that the path ends with a separator + if (path[path.size()-1] != directory::get_separator()) + path += directory::get_separator(); + + // get a handle to something we can search with + ffind = opendir(state.full_name.c_str()); + if (ffind == 0) + { + throw directory::listing_error("Unable to list the contents of " + state.full_name); + } + + while(true) + { + errno = 0; + if ( (data = readdir(ffind)) == 0) + { + // there was an error or no more files + if ( errno == 0) + { + // there are no more files + break; + } + else + { + // there was an error + throw directory::listing_error("Unable to list the contents of " + state.full_name); + } + } + + uint64 file_size; + // get a stat64 structure so we can see if this is a file + if (::stat64((path+data->d_name).c_str(), &buffer) != 0) + { + // this might be a broken symbolic link. We can check by calling + // readlink and seeing if it finds anything. + char buf[PATH_MAX]; + ssize_t temp = readlink((path+data->d_name).c_str(),buf,sizeof(buf)); + if (temp == -1) + throw directory::listing_error("Unable to list the contents of " + state.full_name); + else + file_size = static_cast<uint64>(temp); + } + else + { + file_size = static_cast<uint64>(buffer.st_size); + } + auto last_modified = std::chrono::system_clock::from_time_t(buffer.st_mtime); +#ifdef _BSD_SOURCE + last_modified += std::chrono::duration_cast<std::chrono::system_clock::duration>(std::chrono::nanoseconds(buffer.st_atim.tv_nsec)); +#endif + + if (S_ISDIR(buffer.st_mode) == 0) + { + // this is actually a file + file temp( + data->d_name, + path+data->d_name, + file_size, + last_modified, + file::private_constructor() + ); + files.enqueue(temp); + } + } // while (true) + + if (ffind != 0) + { + while (closedir(ffind)) + { + if (errno != EINTR) + break; + } + ffind = 0; + } + + } + catch (...) + { + if (ffind != 0) + { + while (closedir(ffind)) + { + if (errno != EINTR) + break; + } + ffind = 0; + } + files.clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_files + > + typename enable_if<is_std_vector<queue_of_files>,void>::type + directory_helper_get_files ( + const directory::data& state, + queue_of_files& files + ) + { + queue<file>::kernel_2a temp_files; + directory_helper_get_files(state,temp_files); + + files.clear(); + + // copy the queue of files into the vector + temp_files.reset(); + while (temp_files.move_next()) + { + files.push_back(temp_files.element()); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_files + > + void directory:: + get_files ( + queue_of_files& files + ) const + { + // the reason for this indirection here is because it avoids a bug in + // the cygwin version of gcc + directory_helper_get_files(state,files); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dirs + > + typename disable_if<is_std_vector<queue_of_dirs>,void>::type + directory_helper_get_dirs ( + const directory::data& state, + queue_of_dirs& dirs + ) + { + using namespace std; + + dirs.clear(); + if (state.full_name.size() == 0) + throw directory::listing_error("This directory object currently doesn't represent any directory."); + + DIR* ffind = 0; + struct dirent* data; + struct stat64 buffer; + + try + { + string path = state.full_name; + // ensure that the path ends with a separator + if (path[path.size()-1] != directory::get_separator()) + path += directory::get_separator(); + + // get a handle to something we can search with + ffind = opendir(state.full_name.c_str()); + if (ffind == 0) + { + throw directory::listing_error("Unable to list the contents of " + state.full_name); + } + + while(true) + { + errno = 0; + if ( (data = readdir(ffind)) == 0) + { + // there was an error or no more files + if ( errno == 0) + { + // there are no more files + break; + } + else + { + // there was an error + throw directory::listing_error("Unable to list the contents of " + state.full_name); + } + } + + // get a stat64 structure so we can see if this is a file + if (::stat64((path+data->d_name).c_str(), &buffer) != 0) + { + // just assume this isn't a directory. It is probably a broken + // symbolic link. + continue; + } + + string dtemp(data->d_name); + if (S_ISDIR(buffer.st_mode) && + dtemp != "." && + dtemp != ".." ) + { + // this is a directory so add it to dirs + directory temp(dtemp,path+dtemp, directory::private_constructor()); + dirs.enqueue(temp); + } + } // while (true) + + if (ffind != 0) + { + while (closedir(ffind)) + { + if (errno != EINTR) + break; + } + ffind = 0; + } + + } + catch (...) + { + if (ffind != 0) + { + while (closedir(ffind)) + { + if (errno != EINTR) + break; + } + ffind = 0; + } + dirs.clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dirs + > + typename enable_if<is_std_vector<queue_of_dirs>,void>::type + directory_helper_get_dirs ( + const directory::data& state, + queue_of_dirs& dirs + ) + { + queue<directory>::kernel_2a temp_dirs; + directory_helper_get_dirs(state,temp_dirs); + + dirs.clear(); + + // copy the queue of dirs into the vector + temp_dirs.reset(); + while (temp_dirs.move_next()) + { + dirs.push_back(temp_dirs.element()); + } + } + +// ---------------------------------------------------------------------------------------- + + + template < + typename queue_of_dirs + > + void directory:: + get_dirs ( + queue_of_dirs& dirs + ) const + { + // the reason for this indirection here is because it avoids a bug in + // the cygwin version of gcc + directory_helper_get_dirs(state,dirs); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dir + > + typename disable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots ( + queue_of_dir& roots + ) + { + roots.clear(); + directory dir("/"); + roots.enqueue(dir); + } + + template < + typename queue_of_dir + > + typename enable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots ( + std::vector<directory>& roots + ) + { + roots.clear(); + directory dir("/"); + roots.push_back(dir); + } + +// ---------------------------------------------------------------------------------------- + +} + + +#ifdef NO_MAKEFILE +#include "dir_nav_kernel_2.cpp" +#endif + +#endif // DLIB_DIR_NAV_KERNEl_2_ + diff --git a/ml/dlib/dlib/dir_nav/dir_nav_kernel_abstract.h b/ml/dlib/dlib/dir_nav/dir_nav_kernel_abstract.h new file mode 100644 index 000000000..53254ee03 --- /dev/null +++ b/ml/dlib/dlib/dir_nav/dir_nav_kernel_abstract.h @@ -0,0 +1,515 @@ +// Copyright (C) 2003 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DIR_NAV_KERNEl_ABSTRACT_ +#ifdef DLIB_DIR_NAV_KERNEl_ABSTRACT_ + +#include <string> +#include <vector> +#include "../uintn.h" +#include "../algs.h" +#include <chrono> + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + /*! + GENERAL WARNING + Don't call any of these functions or make any of these objects + before main() has been entered. That means no instances + of file or directory at the global scope. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dir + > + void get_filesystem_roots ( + queue_of_dir& roots + ); + /*! + requires + - queue_of_dirs == an implementation of queue/queue_kernel_abstract.h with T + set to directory or a std::vector<directory> or dlib::std_vector_c<directory>. + ensures + - #roots == a queue containing directories that represent all the roots + of the filesystem on this machine. (e.g. in windows you have c:\, d:\ + etc.) + throws + - std::bad_alloc + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // file object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class file + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a file. + + Note that the size of a file is determined at the time the file + object is constructed. Thus if a file changes sizes after its + file object has been created its file object's size() method + will not reflect the new file size. + !*/ + + public: + + class file_not_found : public error {}; + + file ( + ); + /*! + ensures + - #*this has been properly initialized + - #name() == "" + - #full_name() == "" + - #size() == 0 + - #*this does not represent any file + throws + - std::bad_alloc + !*/ + + file ( + const std::string& name + ); + /*! + ensures + - #*this has been properly initialized + - #*this represents the file given by name + Note that name can be a fully qualified path or just a path + relative to the current working directory. Also, any symbolic + links in name will be resolved. + throws + - std::bad_alloc + - file_not_found + This exception is thrown if the file can not be found or + accessed. + !*/ + + file ( + const char* name + ); + /*! + ensures + - this function is identical to file(const std::string& name) + !*/ + + file ( + const file& item + ); + /*! + ensures + - #*this == item + throws + - std::bad_alloc + !*/ + + ~file ( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + const std::string& name ( + ) const; + /*! + ensures + - returns the name of the file. This is full_name() minus + the path to the file. + !*/ + + const std::string& full_name ( + ) const; + /*! + ensures + - returns the fully qualified name for the file represented by *this + !*/ + + uint64 size ( + ) const; + /*! + ensures + - returns the size of this file in bytes. + !*/ + + std::chrono::time_point<std::chrono::system_clock> last_modified ( + ) const; + /*! + ensures + - returns the time the file was last modified. + !*/ + + operator std::string ( + ) const; + /*! + ensures + - returns full_name() + (i.e. provides an implicit conversion to string from dlib::file) + !*/ + + file& operator= ( + const file& rhs + ); + /*! + ensures + - #*this == rhs + !*/ + + bool operator == ( + const file& rhs + ) const; + /*! + ensures + - if (*this and rhs represent the same file) then + - returns true + - else + - returns false + !*/ + + bool operator != ( + const file& rhs + ) const; + /*! + ensures + - if (*this and rhs represent the same file) then + - returns false + - else + - returns true + !*/ + + bool operator < ( + const file& item + ) const; + /*! + ensures + - if (full_name() < item.full_name()) then + - returns true + - else + - returns false + !*/ + + void swap ( + file& item + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // directory object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class directory + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a directory in a file system. It gives + the ability to traverse a directory tree. + + Note that the directories . and .. are not returned by get_dirs() + !*/ + + public: + + class dir_not_found : public error {}; + class listing_error : public error {}; + + directory ( + ); + /*! + ensures + - #*this has been properly initialized + - #full_name() == "" + - #name() == "" + - #is_root() == true + - #*this does not represent any directory + throws + - std::bad_alloc + !*/ + + directory ( + const std::string& name + ); + /*! + ensures + - #*this has been properly initialized + - #*this represents the directory given by name. + Note that name can be a fully qualified path or just a path + relative to the current working directory. Also, any symbolic + links in name will be resolved. + throws + - std::bad_alloc + - dir_not_found + This exception is thrown if the directory can not be found or + accessed. + !*/ + + directory ( + const char* name + ); + /*! + ensures + - this function is identical to directory(const std::string& name) + !*/ + + directory ( + const directory& item + ); + /*! + ensures + - #*this == item + throws + - std::bad_alloc + !*/ + + ~directory ( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + static char get_separator ( + ); + /*! + ensures + - returns the character used to separate directories and file names in a + path. (i.e. \ on windows and / in unix) + !*/ + + template < + typename queue_of_files + > + void get_files ( + queue_of_files& files + ) const; + /*! + requires + - queue_of_files == an implementation of queue/queue_kernel_abstract.h with T + set to file or a std::vector<file> or dlib::std_vector_c<file>. + ensures + - #files == A queue containing all the files present in this directory. + (Note that symbolic links will not have been resolved in the names + of the returned files.) + - #files.size() == the number of files in this directory + throws + - bad_alloc + If this exception is thrown then the call to get_files() has + no effect on *this and #files is unusable until files.clear() + is called and succeeds. + - listing_error + This exception is thrown if listing access has been denied to this + directory or if some error occurred that prevented us from successfully + getting the contents of this directory. + If this exception is thrown then the call to get_files() has + no effect on *this and #files.size()==0. + !*/ + + std::vector<file> get_files ( + ) const; + /*! + ensures + - This function simply calls get_files(temp_vector) and then returns temp_vector. + !*/ + + template < + typename queue_of_dirs + > + void get_dirs ( + queue_of_dirs& dirs + ) const; + /*! + requires + - queue_of_dirs == an implementation of queue/queue_kernel_abstract.h with T + set to directory or a std::vector<directory> or dlib::std_vector_c<directory>. + ensures + - #dirs == a queue containing all the directories present in this directory. + (note that symbolic links will not have been resolved in the names + of the returned directories.) + - #dirs.size() == the number of subdirectories in this directory + throws + - bad_alloc + If this exception is thrown then the call to get_files() has + no effect on *this and #files is unusable until files.clear() + is called and succeeds. + - listing_error + This exception is thrown if listing access has been denied to this + directory or if some error occurred that prevented us from successfully + getting the contents of this directory. + If this exception is thrown then the call to get_dirs() has + no effect on *this and #dirs.size()==0. + !*/ + + std::vector<directory> get_dirs ( + ) const; + /*! + ensures + - This function simply calls get_dirs(temp_vector) and then returns temp_vector. + !*/ + + bool is_root ( + ) const; + /*! + ensures + - if (*this represents the root of this directory tree) then + - returns true + - else + - returns false + !*/ + + const directory get_parent ( + ) const; + /*! + ensures + - if (is_root()) then + - returns a copy of *this + - else + - returns the parent directory of *this + throws + - bad_alloc + If this exception is thrown then the call to get_parent() will + have no effect. + !*/ + + const std::string& name ( + ) const; + /*! + ensures + - if (is_root()) then + - returns "" + - else + - returns the name of the directory. This is full_name() minus + the path to the directory. + !*/ + + const std::string& full_name ( + ) const; + /*! + ensures + - returns the fully qualified directory name for *this + - if (is_root()) then + - the last character of #full_name() is get_separator() + - else + - the last character of #full_name() is NOT get_separator() + !*/ + + operator std::string ( + ) const; + /*! + ensures + - returns full_name() + (i.e. provides an implicit conversion to string from dlib::directory) + !*/ + + directory& operator= ( + const directory& rhs + ); + /*! + ensures + - #*this == rhs + !*/ + + bool operator == ( + const directory& rhs + ) const; + /*! + ensures + - if (*this and rhs represent the same directory) then + - returns true + - else + - returns false + !*/ + + bool operator != ( + const directory& rhs + ) const; + /*! + ensures + - if (*this and rhs represent the same directory) then + - returns false + - else + - returns true + !*/ + + bool operator < ( + const directory& item + ) const; + /*! + ensures + - if (full_name() < item.full_name()) then + - returns true + - else + - returns false + !*/ + + void swap ( + directory& item + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + inline std::ostream& operator<< ( + std::ostream& out, + const directory& item + ); + /*! + ensures + - performs: out << item.full_name() + - returns out + !*/ + + inline std::ostream& operator<< ( + std::ostream& out, + const file& item + ); + /*! + ensures + - performs: out << item.full_name() + - returns out + !*/ + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + file& a, + file& b + ) { a.swap(b); } + /*! + provides a global swap function for file objects + !*/ + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + directory& a, + directory& b + ) { a.swap(b); } + /*! + provides a global swap function for directory objects + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DIR_NAV_KERNEl_ABSTRACT_ + diff --git a/ml/dlib/dlib/dir_nav/posix.h b/ml/dlib/dlib/dir_nav/posix.h new file mode 100644 index 000000000..8d499064f --- /dev/null +++ b/ml/dlib/dlib/dir_nav/posix.h @@ -0,0 +1,6 @@ +// Copyright (C) 2003 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_KERNEl_1_ +#include "dir_nav_kernel_2.h" +#endif + diff --git a/ml/dlib/dlib/dir_nav/windows.h b/ml/dlib/dlib/dir_nav/windows.h new file mode 100644 index 000000000..b0f1e1bf5 --- /dev/null +++ b/ml/dlib/dlib/dir_nav/windows.h @@ -0,0 +1,6 @@ +// Copyright (C) 2003 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_KERNEl_2_ +#include "dir_nav_kernel_1.h" +#endif + |