summaryrefslogtreecommitdiffstats
path: root/ml/dlib/dlib/dir_nav
diff options
context:
space:
mode:
Diffstat (limited to 'ml/dlib/dlib/dir_nav')
-rw-r--r--ml/dlib/dlib/dir_nav/dir_nav_extensions.cpp121
-rw-r--r--ml/dlib/dlib/dir_nav/dir_nav_extensions.h172
-rw-r--r--ml/dlib/dlib/dir_nav/dir_nav_extensions_abstract.h203
-rw-r--r--ml/dlib/dlib/dir_nav/dir_nav_kernel_1.cpp258
-rw-r--r--ml/dlib/dlib/dir_nav/dir_nav_kernel_1.h634
-rw-r--r--ml/dlib/dlib/dir_nav/dir_nav_kernel_2.cpp254
-rw-r--r--ml/dlib/dlib/dir_nav/dir_nav_kernel_2.h659
-rw-r--r--ml/dlib/dlib/dir_nav/dir_nav_kernel_abstract.h515
-rw-r--r--ml/dlib/dlib/dir_nav/posix.h6
-rw-r--r--ml/dlib/dlib/dir_nav/windows.h6
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
+