// filepath.hpp
// Chad Austin -- aegis@nerv-un.net
// http://www.nerv-un.net/~aegis/
// 2000.07.14
//
// path_delim<T> class
// file_path<T> class
#ifdef _MSC_VER
#pragma warning(disable : 4786) // identifier too long
#endif
#ifndef FILEPATH_HPP
#define FILEPATH_HPP
#include <sstream>
#include <list>
#include <string>
#include <locale>
#include <cstdlib>
namespace fp
{
// path_delimiters<charT>
template<typename charT>
class path_delimiters
{
public:
static bool is_path_delim(charT c);
static bool is_drive_delim(charT c);
static bool is_scheme_delim(charT c);
static bool is_port_delim(charT c);
static bool is_query_delim(charT c);
static bool is_extension_delim(charT c);
static charT path_delim();
static charT drive_delim();
static charT scheme_delim();
static charT port_delim();
static charT query_delim();
static charT extension_delim();
static const charT* unknown_scheme();
};
// path_delimiters<char>
template<>
class path_delimiters<char>
{
public:
static bool is_path_delim(charT c) { return (c == '/') || (c == '\\'); }
static bool is_drive_delim(charT c) { return (c == ':'); }
static bool is_scheme_delim(charT c) { return (c == ':'); }
static bool is_port_delim(charT c) { return (c == ':'); }
static bool is_query_delim(charT c) { return (c == '?'); }
static bool is_extension_delim(charT c) { return (c == '.'); }
static charT path_delim() { return '/'; }
static charT drive_delim() { return ':'; }
static charT scheme_delim() { return ':'; }
static charT port_delim() { return ':'; }
static charT query_delim() { return '?'; }
static charT extension_delim() { return '.'; }
static const charT* unknown_scheme() { return "unknown"; }
};
// path_delimiters<wchar_t>
template<>
class path_delimiters<wchar_t>
{
public:
static bool is_path_delim(charT c) { return (c == L'/') || (c == L'\\'); }
static bool is_drive_delim(charT c) { return (c == L':'); }
static bool is_scheme_delim(charT c) { return (c == L':'); }
static bool is_port_delim(charT c) { return (c == L':'); }
static bool is_query_delim(charT c) { return (c == L'?'); }
static bool is_extension_delim(charT c) { return (c == L'.'); }
static charT path_delim() { return L'/'; }
static charT drive_delim() { return L':'; }
static charT scheme_delim() { return L':'; }
static charT port_delim() { return L':'; }
static charT query_delim() { return L'?'; }
static charT extension_delim() { return L'.'; }
static const charT* unknown_scheme() { return L"unknown"; }
};
// basic_filepath<charT, delimT>
template<typename charT, typename delimT = path_delimiters<charT> >
class basic_filepath
{
public:
typedef std::basic_string<charT> string;
// constructors
basic_filepath() {
// empty path
parse(string().c_str());
}
basic_filepath(const charT* path) {
parse(path);
}
// operator overloads
basic_filepath<charT, delimT>&
operator=(const basic_filepath<charT, delimT>& rhs) {
if (this != &rhs) {
parse(rhs.str().c_str());
}
}
// stringify
string str() const {
basic_ostringstream<charT> s;
// add URL elements
if (is_url()) {
s << m_scheme;
s << delimT::scheme_delim();
s << delimT::path_delim();
s << delimT::path_delim();
s << m_server;
if (m_port != 0) {
s << delimT::port_delim();
s << m_port;
}
}
// add Windows elements
if (is_windows()) {
s << m_drive;
s << delimT::drive_delim();
}
// add leading path delimiter if absolute
if (m_is_absolute) {
s << delimT::path_delim();
}
// add directories
for (std::list<string>::const_iterator i = m_path_segments.begin();
i != m_path_segments.end();
i++) {
s << *i << delimT::path_delim();
}
// add file and extension
if (m_file.length() > 0) {
s << m_file;
if (m_extension.length() > 0) {
s << delimT::extension_delim() << m_extension;
}
}
// final URL elements
if (is_url() && m_query.length() > 0) {
s << delimT::query_delim() << m_query;
}
return s.str();
}
// Windows/DOS
bool is_windows() const {
return (m_drive != charT());
}
void set_drive(charT drive) const {
m_drive = drive;
}
charT get_drive() const {
return m_drive;
}
// URL
bool is_url() const {
return (m_scheme.length() != 0);
}
void set_scheme(const string& scheme) {
m_scheme = scheme;
}
string get_scheme() const {
return m_scheme;
}
void set_server(const string& server) {
if (is_url() == false) {
m_scheme = delimT::unknown_scheme();
}
m_server = server;
}
string get_server() const {
return m_server;
}
void set_port(int port) {
if (is_url() == false) {
m_scheme = delimT::unknown_scheme();
}
m_port = port;
}
int get_port() const {
return m_port;
}
void set_query(const string& query) {
if (is_url() == false) {
m_scheme = delimT::unknown_scheme();
}
m_query = query;
}
string get_query() const {
return m_query;
}
// general
bool is_absolute() const {
return m_is_absolute;
}
string get_path() const {
string r;
if (m_is_absolute) {
r = delimT::path_delim();
}
for (std::list<string>::const_iterator i = m_path_segments.begin();
i != m_path_segments.end();
i++) {
r += *i;
r += delimT::path_delim();
}
return r;
}
bool has_file() const {
return (m_file.length() != 0);
}
void set_file(const string& file) {
m_file = file;
}
string get_file() const {
return m_file;
}
void set_extension(const string& extension) {
m_extension = extension;
}
string get_extension() {
return m_extension;
}
private:
void parse(const charT* s) {
// initialize
m_is_absolute = false;
m_drive = charT();
m_scheme = string();
m_server = string();
m_port = 0;
m_query = string();
m_path_segments.clear();
m_file = string();
m_extension = string();
// check for Windows path first
if (std::isalpha(s[0], std::locale::empty()) &&
delimT::is_drive_delim(s[1]) &&
delimT::is_path_delim(s[2])) {
m_drive = s[0];
m_is_absolute = true;
s += 3;
}
const charT* p = s;
if (!is_windows()) {
// check for URL
while (*p) {
if (delimT::is_scheme_delim(*p)) {
m_scheme = string(s, p - s);
s = p + 1;
// possibly skip the next two path delimiters
if (delimT::is_path_delim(*s)) {
s++;
}
if (delimT::is_path_delim(*s)) {
s++;
}
break;
}
p++;
}
// if we found a URL, parse server/port
if (m_scheme.length() > 0) {
// server
while (*s) {
if (delimT::is_port_delim(*s) ||
delimT::is_path_delim(*s)) {
break;
}
m_server += *s;
s++;
}
// port
if (delimT::is_port_delim(*s)) {
s++;
string port;
while (*s && !delimT::is_path_delim(*s)) {
port += *s;
s++;
}
basic_istringstream<charT> is(port);
is >> m_port;
}
}
}
// parse path list
string c;
while (*s) {
// if it's a path delimiter, add it to the path list
if (delimT::is_path_delim(*s)) {
if (c.length() > 0) {
m_path_segments.push_back(c);
} else {
// if first segment is empty
// (first path character is /),
// path is absolute
if (m_path_segments.size() == 0) {
m_is_absolute = true;
}
}
c = string();
s++;
continue;
}
c += *s;
s++;
}
// parse filename in c
const charT* q = c.c_str();
p = q;
while (*p) {
if (delimT::is_query_delim(*p)) {
// grab the query string
m_query = p + 1;
break;
}
p++;
}
// get a file+extension string
string file(q, p - q);
int pos = -1;
for (int i = file.length() - 1; i >= 0; i--) {
if (delimT::is_extension_delim(file[i])) {
pos = i;
break;
}
}
if (pos == -1) {
m_file = file;
} else {
m_file = file.substr(0, pos);
m_extension = file.substr(pos + 1, file.length() - pos - 1);
}
}
private:
bool m_is_absolute;
// windows
charT m_drive;
// URL
string m_scheme;
string m_server;
int m_port;
string m_query;
// general
std::list<string> m_path_segments;
string m_file;
string m_extension;
};
typedef basic_filepath<char> filepath;
typedef basic_filepath<wchar_t> wfilepath;
} // end namespace
#endif // FILEPATH_HPP
|