Logo Search packages:      
Sourcecode: poco version File versions  Download package

Path.cpp
//
// Path.cpp
//
// $Id: //poco/1.3/Foundation/src/Path.cpp#5 $
//
// Library: Foundation
// Package: Filesystem
// Module:  Path
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
// 
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//


#include "Poco/Path.h"
#include "Poco/File.h"
#include "Poco/Exception.h"
#include "Poco/StringTokenizer.h"
#if defined(_WIN32) && defined(POCO_WIN32_UTF8)
#include "Poco/UnicodeConverter.h"
#include "Poco/Buffer.h"
#endif
#include <algorithm>


#if defined(POCO_OS_FAMILY_VMS)
#include "Path_VMS.cpp"
#elif defined(POCO_OS_FAMILY_UNIX)
#include "Path_UNIX.cpp"
#elif defined(POCO_OS_FAMILY_WINDOWS) && defined(POCO_WIN32_UTF8)
#include "Path_WIN32U.cpp"
#elif defined(POCO_OS_FAMILY_WINDOWS)
#include "Path_WIN32.cpp"
#endif


namespace Poco {


Path::Path(): _absolute(false)
{
}


00067 Path::Path(bool absolute): _absolute(absolute)
{
}


00072 Path::Path(const std::string& path)
{
      assign(path);
}


00078 Path::Path(const std::string& path, Style style)
{
      assign(path, style);
}


00084 Path::Path(const char* path)
{
      poco_check_ptr(path);
      assign(path);
}


00091 Path::Path(const char* path, Style style)
{
      poco_check_ptr(path);
      assign(path, style);
}


00098 Path::Path(const Path& path): 
      _node(path._node), 
      _device(path._device),
      _name(path._name),
      _version(path._version),
      _dirs(path._dirs),
      _absolute(path._absolute)
{     
}


00109 Path::Path(const Path& parent, const std::string& fileName):
      _node(parent._node), 
      _device(parent._device),
      _name(parent._name),
      _version(parent._version),
      _dirs(parent._dirs),
      _absolute(parent._absolute)
{     
      makeDirectory();
      _name = fileName;
}


00122 Path::Path(const Path& parent, const char* fileName):
      _node(parent._node), 
      _device(parent._device),
      _name(parent._name),
      _version(parent._version),
      _dirs(parent._dirs),
      _absolute(parent._absolute)
{     
      makeDirectory();
      _name = fileName;
}


00135 Path::Path(const Path& parent, const Path& relative):
      _node(parent._node), 
      _device(parent._device),
      _name(parent._name),
      _version(parent._version),
      _dirs(parent._dirs),
      _absolute(parent._absolute)
{     
      resolve(relative);
}


00147 Path::~Path()
{
}

      
00152 Path& Path::operator = (const Path& path)
{
      return assign(path);
}

      
00158 Path& Path::operator = (const std::string& path)
{
      return assign(path);
}


00164 Path& Path::operator = (const char* path)
{
      poco_check_ptr(path);
      return assign(path);
}


00171 void Path::swap(Path& path)
{
      std::swap(_node, path._node);
      std::swap(_device, path._device);
      std::swap(_name, path._name);
      std::swap(_version, path._version);
      std::swap(_dirs, path._dirs);
      std::swap(_absolute, path._absolute);
}


00182 Path& Path::assign(const Path& path)
{
      if (&path != this)
      {
            _node     = path._node;
            _device   = path._device;
            _name     = path._name;
            _version  = path._version;
            _dirs     = path._dirs;
            _absolute = path._absolute;
      }
      return *this;
}


00197 Path& Path::assign(const std::string& path)
{
#if defined(POCO_OS_FAMILY_VMS)
      parseVMS(path);
#elif defined(POCO_OS_FAMILY_WINDOWS)
      parseWindows(path);
#else
      parseUnix(path);
#endif
      return *this;
}

      
00210 Path& Path::assign(const std::string& path, Style style)
{
      switch (style)
      {
      case PATH_UNIX:
            parseUnix(path);
            break;
      case PATH_WINDOWS:
            parseWindows(path);
            break;
      case PATH_VMS:
            parseVMS(path);
            break;
      case PATH_NATIVE:
            assign(path);
            break;
      case PATH_GUESS:
            parseGuess(path);
            break;
      default:
            poco_bugcheck();
      }
      return *this;
}


00236 Path& Path::assign(const char* path)
{
      return assign(std::string(path));
}


00242 std::string Path::toString() const
{
#if defined(POCO_OS_FAMILY_UNIX)
      return buildUnix();
#elif defined(POCO_OS_FAMILY_WINDOWS)
      return buildWindows();
#else
      return buildVMS();
#endif
}

      
00254 std::string Path::toString(Style style) const
{
      switch (style)
      {
      case PATH_UNIX:
            return buildUnix();
      case PATH_WINDOWS:
            return buildWindows();
      case PATH_VMS:
            return buildVMS();
      case PATH_NATIVE:
      case PATH_GUESS:
            return toString();
      default:
            poco_bugcheck();
      }
      return std::string();
}


00274 bool Path::tryParse(const std::string& path)
{
      try
      {
            Path p;
            p.parse(path);
            assign(p);
            return true;
      }
      catch (...)
      {
            return false;
      }
}


00290 bool Path::tryParse(const std::string& path, Style style)
{
      try
      {
            Path p;
            p.parse(path, style);
            assign(p);
            return true;
      }
      catch (...)
      {
            return false;
      }
}


00306 Path& Path::parseDirectory(const std::string& path)
{
      assign(path);
      return makeDirectory();
}


00313 Path& Path::parseDirectory(const std::string& path, Style style)
{
      assign(path, style);
      return makeDirectory();
}


00320 Path& Path::makeDirectory()
{
#if defined(POCO_OS_FAMILY_VMS)
      pushDirectory(getBaseName());
#else
      pushDirectory(_name);
#endif
      _name.clear();
      _version.clear();
      return *this;
}


00333 Path& Path::makeFile()
{
      if (!_dirs.empty() && _name.empty())
      {
            _name = _dirs.back();
            _dirs.pop_back();
#if defined(POCO_OS_FAMILY_VMS)
            setExtension("DIR");
#endif
      }
      return *this;
}


00347 Path& Path::makeAbsolute()
{
      return makeAbsolute(current());
}


00353 Path& Path::makeAbsolute(const Path& base)
{
      if (!_absolute)
      {
            Path tmp = base;
            tmp.makeDirectory();
            for (StringVec::const_iterator it = _dirs.begin(); it != _dirs.end(); ++it)
            {
                  tmp.pushDirectory(*it);
            }
            _node     = tmp._node;
            _device   = tmp._device;
            _dirs     = tmp._dirs;
            _absolute = base._absolute;
      }
      return *this;
}


00372 Path Path::absolute() const
{
      Path result(*this);
      if (!result._absolute)
      {
            result.makeAbsolute();
      }
      return result;
}


00383 Path Path::absolute(const Path& base) const
{
      Path result(*this);
      if (!result._absolute)
      {
            result.makeAbsolute(base);
      }
      return result;
}


00394 Path Path::parent() const
{
      Path p(*this);
      return p.makeParent();
}


00401 Path& Path::makeParent()
{
      if (_name.empty())
      {
            if (_dirs.empty())
            {
                  if (!_absolute)
                        _dirs.push_back("..");
            }
            else
            {
                  if (_dirs.back() == "..")
                        _dirs.push_back("..");
                  else
                        _dirs.pop_back();
            }
      }
      else
      {
            _name.clear();
            _version.clear();
      }
      return *this;
}


00427 Path& Path::append(const Path& path)
{
      makeDirectory();
      _dirs.insert(_dirs.end(), path._dirs.begin(), path._dirs.end());
      _name = path._name;
      _version = path._version;
      return *this;
}


00437 Path& Path::resolve(const Path& path)
{
      if (path.isAbsolute())
      {
            assign(path);
      }
      else
      {
            for (int i = 0; i < path.depth(); ++i)
                  pushDirectory(path[i]);
            _name = path._name;
      }
      return *this;
}


00453 void Path::setNode(const std::string& node)
{
      _node     = node;
      _absolute = _absolute || !node.empty();
}

      
00460 void Path::setDevice(const std::string& device)
{
      _device   = device;
      _absolute = _absolute || !device.empty();
}

      
00467 const std::string& Path::directory(int n) const
{
      poco_assert (0 <= n && n <= _dirs.size());
      
      if (n < _dirs.size())
            return _dirs[n];
      else
            return _name;     
}


00478 const std::string& Path::operator [] (int n) const
{
      poco_assert (0 <= n && n <= _dirs.size());
      
      if (n < _dirs.size())
            return _dirs[n];
      else
            return _name;     
}

      
00489 void Path::pushDirectory(const std::string& dir)
{
      if (!dir.empty() && dir != ".")
      {
#if defined(POCO_OS_FAMILY_VMS)
            if (dir == ".." || dir == "-")
            {
                  if (!_dirs.empty() && _dirs.back() != ".." && _dirs.back() != "-")
                        _dirs.pop_back();
                  else if (!_absolute)
                        _dirs.push_back(dir);
            }
            else _dirs.push_back(dir);
#else
            if (dir == "..")
            {
                  if (!_dirs.empty() && _dirs.back() != "..")
                        _dirs.pop_back();
                  else if (!_absolute)
                        _dirs.push_back(dir);
            }
            else _dirs.push_back(dir);
#endif
      }
}

      
00516 void Path::popDirectory()
{
      poco_assert (!_dirs.empty());
      
      _dirs.pop_back();
}

      
00524 void Path::setFileName(const std::string& name)
{
      _name = name;
}


00530 void Path::setBaseName(const std::string& name)
{
      std::string ext = getExtension();
      _name = name;
      if (!ext.empty())
      {
            _name.append(".");
            _name.append(ext);
      }
}


00542 std::string Path::getBaseName() const
{
      std::string::size_type pos = _name.rfind('.');
      if (pos != std::string::npos)
            return _name.substr(0, pos);
      else
            return _name;
}


00552 void Path::setExtension(const std::string& extension)
{
      _name = getBaseName();
      if (!extension.empty())
      {
            _name.append(".");
            _name.append(extension);
      }
}

                  
00563 std::string Path::getExtension() const
{
      std::string::size_type pos = _name.rfind('.');
      if (pos != std::string::npos)
            return _name.substr(pos + 1);
      else
            return std::string();
}


00573 void Path::clear()
{
      _node.clear();
      _device.clear();
      _name.clear();
      _dirs.clear();
      _version.clear();
      _absolute = false;
}


00584 std::string Path::current()
{
      return PathImpl::currentImpl();
}

      
00590 std::string Path::home()
{
      return PathImpl::homeImpl();
}

      
00596 std::string Path::temp()
{
      return PathImpl::tempImpl();
}


00602 std::string Path::null()
{
      return PathImpl::nullImpl();
}

      
00608 std::string Path::expand(const std::string& path)
{
      return PathImpl::expandImpl(path);
}


00614 void Path::listRoots(std::vector<std::string>& roots)
{
      PathImpl::listRootsImpl(roots);
}


00620 bool Path::find(StringVec::const_iterator it, StringVec::const_iterator end, const std::string& name, Path& path)
{
      while (it != end)
      {
            Path p(*it);
            p.makeDirectory();
            p.resolve(Path(name));
            File f(p);
            if (f.exists())
            {
                  path = p;
                  return true;
            }
            ++it;
      }
      return false;
}


00639 bool Path::find(const std::string& pathList, const std::string& name, Path& path)
{
      StringTokenizer st(pathList, std::string(1, pathSeparator()), StringTokenizer::TOK_IGNORE_EMPTY + StringTokenizer::TOK_TRIM);
      return find(st.begin(), st.end(), name, path);
}


00646 void Path::parseUnix(const std::string& path)
{
      clear();

      std::string::const_iterator it  = path.begin();
      std::string::const_iterator end = path.end();

      if (it != end)
      {
            if (*it == '/') 
            {
                  _absolute = true; ++it;
            }
            else if (*it == '~')
            {
                  ++it;
                  if (it == end || *it == '/')
                  {
                        Path cwd(home());
                        _dirs = cwd._dirs;
                        _absolute = true;
                  }
                  else --it;
            }

            while (it != end)
            {
                  std::string name;
                  while (it != end && *it != '/') name += *it++;
                  if (it != end)
                  {
                        if (_dirs.empty())
                        {
                              if (!name.empty() && *(name.rbegin()) == ':')
                                    _device.assign(name, 0, name.length() - 1);
                              else
                                    pushDirectory(name);
                        }
                        else pushDirectory(name);
                  }
                  else _name = name;
                  if (it != end) ++it;
            }
      }
}


void Path::parseWindows(const std::string& path)
{
      clear();

      std::string::const_iterator it  = path.begin();
      std::string::const_iterator end = path.end();

      if (it != end)
      {
            if (*it == '\\' || *it == '/') { _absolute = true; ++it; }
            if (_absolute && it != end && (*it == '\\' || *it == '/')) // UNC
            {
                  ++it;
                  while (it != end && *it != '\\' && *it != '/') _node += *it++;
                  if (it != end) ++it;
            }
            else if (it != end)
            {
                  char d = *it++;
                  if (it != end && *it == ':') // drive letter
                  {
                        if (_absolute || !((d >= 'a' && d <= 'z') || (d >= 'A' && d <= 'Z'))) throw PathSyntaxException(path);
                        _absolute = true;
                        _device += d;
                        ++it;
                        if (it == end || (*it != '\\' && *it != '/')) throw PathSyntaxException(path);
                        ++it;
                  }
                  else --it;
            }
            while (it != end)
            {
                  std::string name;
                  while (it != end && *it != '\\' && *it != '/') name += *it++;
                  if (it != end)
                        pushDirectory(name);
                  else
                        _name = name;
                  if (it != end) ++it;
            }
      }
      if (!_node.empty() && _dirs.empty() && !_name.empty())
            makeDirectory();
}


void Path::parseVMS(const std::string& path)
{
      clear();

      std::string::const_iterator it  = path.begin();
      std::string::const_iterator end = path.end();

      if (it != end)
      {
            std::string name;
            while (it != end && *it != ':' && *it != '[' && *it != ';') name += *it++;
            if (it != end)
            {
                  if (*it == ':')
                  {
                        ++it;
                        if (it != end && *it == ':')
                        {
                              _node = name;
                              ++it;
                        }
                        else _device = name;
                        _absolute = true;
                        name.clear();
                  }
                  if (it != end)
                  {
                        if (_device.empty() && *it != '[')
                        {
                              while (it != end && *it != ':' && *it != ';') name += *it++;
                              if (it != end)
                              {
                                    if (*it == ':')
                                    {
                                          _device = name;
                                          _absolute = true;
                                          name.clear();
                                          ++it;
                                    }
                              }
                        }
                  }                 
                  if (name.empty())
                  {
                        if (it != end && *it == '[')
                        {
                              ++it;
                              if (it != end)
                              {
                                    _absolute = true;
                                    if (*it == '.')
                                          { _absolute = false; ++it; }
                                    else if (*it == ']' || *it == '-')
                                          _absolute = false;
                                    while (it != end && *it != ']')
                                    {
                                          name.clear();
                                          if (*it == '-')
                                                name = "-";
                                          else
                                                while (it != end && *it != '.' && *it != ']') name += *it++;
                                          if (!name.empty())
                                          {
                                                if (name == "-")
                                                {
                                                      if (_dirs.empty() || _dirs.back() == "..")
                                                            _dirs.push_back("..");
                                                      else 
                                                            _dirs.pop_back();
                                                }
                                                else _dirs.push_back(name);
                                          }
                                          if (it != end && *it != ']') ++it;
                                    }
                                    if (it == end) throw PathSyntaxException(path);
                                    ++it;
                                    if (it != end && *it == '[')
                                    {
                                          if (!_absolute) throw PathSyntaxException(path);
                                          ++it;
                                          if (it != end && *it == '.') throw PathSyntaxException(path);
                                          int d = int(_dirs.size());
                                          while (it != end && *it != ']')
                                          {
                                                name.clear();
                                                if (*it == '-')
                                                      name = "-";
                                                else
                                                      while (it != end && *it != '.' && *it != ']') name += *it++;
                                                if (!name.empty())
                                                {
                                                      if (name == "-")
                                                      {
                                                            if (_dirs.size() > d)
                                                                  _dirs.pop_back();
                                                      }
                                                      else _dirs.push_back(name);
                                                }
                                                if (it != end && *it != ']') ++it;
                                          }
                                          if (it == end) throw PathSyntaxException(path);
                                          ++it;
                                    }
                              }
                              _name.clear();
                        }
                        while (it != end && *it != ';') _name += *it++;
                  }
                  else _name = name;
                  if (it != end && *it == ';')
                  {
                        ++it;
                        while (it != end) _version += *it++;
                  }
            }
            else _name = name;
      }
}


void Path::parseGuess(const std::string& path)
{
      bool hasBackslash   = false;
      bool hasSlash       = false;
      bool hasOpenBracket = false;
      bool hasClosBracket = false;
      bool isWindows      = path.length() > 2 && path[1] == ':' && (path[2] == '/' || path[2] == '\\');
      std::string::const_iterator end    = path.end();
      std::string::const_iterator semiIt = end;
      if (!isWindows)
      {
            for (std::string::const_iterator it = path.begin(); it != end; ++it)
            {
                  switch (*it)
                  {
                  case '\\': hasBackslash = true; break;
                  case '/':  hasSlash = true; break;
                  case '[':  hasOpenBracket = true;
                  case ']':  hasClosBracket = hasOpenBracket; 
                  case ';':  semiIt = it; break;
                  }
            }
      }
      if (hasBackslash || isWindows)
      {
            parseWindows(path);
      }
      else if (hasSlash)
      {
            parseUnix(path);
      }
      else
      {
            bool isVMS = hasClosBracket;
            if (!isVMS && semiIt != end)
            {
                  isVMS = true;
                  ++semiIt;
                  while (semiIt != end)
                  {
                        if (*semiIt < '0' || *semiIt > '9')
                        {
                              isVMS = false; break;
                        }
                        ++semiIt;
                  }
            }
            if (isVMS)
                  parseVMS(path);
            else
                  parseUnix(path);
      }
}


std::string Path::buildUnix() const
{
      std::string result;
      if (!_device.empty())
      {
            result.append("/");
            result.append(_device);
            result.append(":/");
      }
      else if (_absolute)
      {
            result.append("/");
      }
      for (StringVec::const_iterator it = _dirs.begin(); it != _dirs.end(); ++it)
      {
            result.append(*it);
            result.append("/");
      }
      result.append(_name);
      return result;
}


std::string Path::buildWindows() const
{
      std::string result;
      if (!_node.empty())
      {
            result.append("\\\\");
            result.append(_node);
            result.append("\\");
      }
      else if (!_device.empty())
      {
            result.append(_device);
            result.append(":\\");
      }
      else if (_absolute)
      {
            result.append("\\");
      }
      for (StringVec::const_iterator it = _dirs.begin(); it != _dirs.end(); ++it)
      {
            result.append(*it);
            result.append("\\");
      }
      result.append(_name);
      return result;
}


std::string Path::buildVMS() const
{
      std::string result;
      if (!_node.empty())
      {
            result.append(_node);
            result.append("::");
      }
      if (!_device.empty())
      {
            result.append(_device);
            result.append(":");
      }
      if (!_dirs.empty())
      {
            result.append("[");
            if (!_absolute && _dirs[0] != "..")
                  result.append(".");
            for (StringVec::const_iterator it = _dirs.begin(); it != _dirs.end(); ++it)
            {
                  if (it != _dirs.begin() && *it != "..")
                        result.append(".");
                  if (*it == "..")
                        result.append("-");
                  else
                        result.append(*it);
            }
            result.append("]");
      }
      result.append(_name);
      if (!_version.empty())
      {
            result.append(";");
            result.append(_version);
      }
      return result;
}


01004 std::string Path::transcode(const std::string& path)
{
#if defined(_WIN32) && defined(POCO_WIN32_UTF8)
      std::wstring uniPath;
      UnicodeConverter::toUTF16(path, uniPath);
      DWORD len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, uniPath.c_str(), static_cast<int>(uniPath.length()), NULL, 0, NULL, NULL);
      if (len > 0)
      {
            Buffer<char> buffer(len);
            DWORD rc = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, uniPath.c_str(), static_cast<int>(uniPath.length()), buffer.begin(), static_cast<int>(buffer.size()), NULL, NULL);
            if (rc)
            {
                  return std::string(buffer.begin(), buffer.size());
            }
      }
#endif
      return path;
}


} // namespace Poco

Generated by  Doxygen 1.6.0   Back to index