kinect/codes/Azure-Kinect-Sensor-SDK/tools/k4aviewer/platform/linux/filesystem17.cpp

245 lines
4.6 KiB
C++

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Associated header
//
#include "filesystem17.h"
// System headers
//
#include <cstring>
#include <dirent.h>
#include <libgen.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
// Library headers
//
// Project headers
//
using namespace std17::filesystem;
struct std17::filesystem::directory_iterator_impl
{
directory_iterator_impl(const path &p)
{
m_end = false;
m_dir = opendir(p.c_str());
if (!m_dir)
{
m_end = true;
return;
}
advance();
}
directory_iterator_impl &advance()
{
m_dirent = readdir(m_dir);
// readdir includes the '.' and '..' special directories, but std::filesystem
// omits them, so we want to mimic that behavior. Unlike Windows, they're not
// always the first two entries, so we have to check every file we look at
//
while (m_dirent != nullptr && (!strcmp(".", m_dirent->d_name) || !strcmp("..", m_dirent->d_name)))
{
m_dirent = readdir(m_dir);
}
if (m_dirent == nullptr)
{
m_end = true;
}
return *this;
}
~directory_iterator_impl()
{
if (m_dir)
{
closedir(m_dir);
}
}
dirent *m_dirent;
DIR *m_dir = nullptr;
bool m_end = false;
};
path::path(const char *p)
{
m_path = p;
}
path &path::append(const char *p)
{
if (m_path.size() != 0 && m_path[m_path.size() - 1] != '/')
{
m_path += "/";
}
m_path += p;
return *this;
}
path &path::concat(const char *p)
{
m_path += p;
return *this;
}
const char *path::c_str() const
{
return m_path.c_str();
}
std::string path::string() const
{
return m_path;
}
bool path::exists(const path &path)
{
struct stat buffer;
const int status = stat(path.c_str(), &buffer);
return status == 0;
}
bool path::is_directory(const path &path)
{
struct stat buffer;
const int status = stat(path.c_str(), &buffer);
if (status != 0)
{
return false;
}
return S_ISDIR(buffer.st_mode);
}
path path::filename() const
{
std::string filename = m_path;
return path(basename(&filename[0]));
}
path path::extension() const
{
std::string filenameStr = filename().string();
size_t lastPeriod = filenameStr.rfind('.');
if (lastPeriod == std::string::npos || lastPeriod == 0 || filenameStr == "..")
{
return path("");
}
return path(filenameStr.substr(lastPeriod).c_str());
}
path path::parent_path() const
{
std::string filename = m_path;
return path(dirname(&filename[0]));
}
bool directory_entry::exists() const
{
return path::exists(m_path);
}
bool directory_entry::is_directory() const
{
return path::is_directory(m_path);
}
path std17::filesystem::current_path()
{
std::vector<char> buffer;
buffer.resize(PATH_MAX, '\0');
if (!getcwd(&buffer[0], PATH_MAX))
{
return path("");
}
return path(&buffer[0]);
}
directory_iterator::directory_iterator() : m_impl(nullptr) {}
directory_iterator::directory_iterator(const path &p) : m_impl(std::make_shared<directory_iterator_impl>(p))
{
if (m_impl->m_end)
{
m_impl.reset();
return;
}
m_directory = p;
update_entry_path();
}
directory_iterator directory_iterator::end(const directory_iterator &)
{
return directory_iterator();
}
directory_iterator &directory_iterator::operator++()
{
if (m_impl)
{
m_impl->advance();
}
if (m_impl->m_end)
{
m_impl.reset();
}
else
{
update_entry_path();
}
return *this;
}
bool directory_iterator::operator!=(const directory_iterator &other)
{
// This is not strictly true, but we only need operator!= to support iterator loops
// (i.e. they only need to return equal if they're both the end iterator)
//
return !(m_impl == nullptr && other.m_impl == nullptr);
}
const directory_entry &directory_iterator::operator*() const
{
if (!m_impl)
{
// then they're trying to deference an invalid iterator - segfault
//
directory_entry *e = nullptr;
return *e;
}
return m_current;
}
const directory_entry *directory_iterator::operator->() const
{
if (!m_impl)
{
return nullptr;
}
return &m_current;
}
void directory_iterator::update_entry_path()
{
m_current.m_path = m_directory;
m_current.m_path.append(m_impl->m_dirent->d_name);
}