#include "FileZilla.h"
#include "serverpath.h"
#define FTP_MVS_DOUBLE_QUOTE (wxChar)0xDC
CServerPath::CServerPath()
{
m_type = DEFAULT;
m_bEmpty = true;
}
CServerPath::CServerPath(const CServerPath &path, wxString subdir /*=_T("")*/)
{
m_type = path.m_type;
m_bEmpty = path.m_bEmpty;
m_prefix = path.m_prefix;
m_Segments = path.m_Segments;
subdir.Trim(true);
subdir.Trim(false);
if (subdir == _T(""))
return;
if (!ChangePath(subdir))
Clear();
}
CServerPath::CServerPath(wxString path, ServerType type /*=DEFAULT*/)
{
m_type = type;
SetPath(path);
}
CServerPath::~CServerPath()
{
}
void CServerPath::Clear()
{
m_bEmpty = true;
m_type = DEFAULT;
m_prefix = _T("");
m_Segments.clear();
}
bool CServerPath::SetPath(wxString newPath)
{
return SetPath(newPath, false);
}
bool CServerPath::SetPath(wxString &newPath, bool isFile)
{
m_Segments.clear();
m_prefix = _T("");
wxString path = newPath;
wxString file;
path.Trim(true);
path.Trim(false);
if (path == _T(""))
{
m_bEmpty = true;
return false;
}
else
m_bEmpty = false;
if (m_type == DEFAULT)
{
int pos1 = path.Find(_T(":["));
if (pos1 != -1)
{
int pos2 = path.Find(']', true);
if (pos2 != -1 && static_cast<size_t>(pos2) == (path.Length() - 1) && !isFile)
m_type = VMS;
else if (isFile && pos2 > pos1)
m_type = VMS;
}
else if (path.Length() >= 3 &&
((path.c_str()[0] >= 'A' && path.c_str()[0] <= 'Z') || (path.c_str()[0] >= 'a' && path.c_str()[0] <= 'z')) &&
path.c_str()[1] == ':' && (path.c_str()[2] == '\\' || path.c_str()[2] == '/'))
m_type = DOS;
else if (path.c_str()[0] == FTP_MVS_DOUBLE_QUOTE && path.Last() == FTP_MVS_DOUBLE_QUOTE)
m_type = MVS;
else if (path[0] == ':' && (pos1 = path.Mid(1).Find(':')) > 0)
{
int slash = path.Find('/');
if (slash == -1 || slash > pos1)
m_type = VXWORKS;
}
if (m_type == DEFAULT)
m_type = UNIX;
}
int pos;
switch (m_type)
{
case VMS:
if (isFile)
{
pos = path.Find(']', true);
if (pos == -1)
{
m_bEmpty = true;
return false;
}
file = path.Mid(pos + 1);
path = path.Left(pos + 1);
}
pos = path.Find(_T("["));
if (pos == -1 || path.Right(1) != _T("]"))
{
m_bEmpty = true;
return false;
}
path.RemoveLast();
if (pos)
m_prefix = path.Left(pos);
path = path.Mid(pos + 1);
pos = path.Find(_T("."));
while (pos != -1)
{
m_Segments.push_back(path.Left(pos));
path = path.Mid(pos + 1);
pos = path.Find(_T("."));
}
if (path != _T(""))
m_Segments.push_back(path);
break;
case MVS:
{
int i = 0;
wxChar c = path.c_str()[i];
while (c == FTP_MVS_DOUBLE_QUOTE || c == '\'' || c == '.')
c = path.c_str()[++i];
path.Remove(0, i);
while (path != _T(""))
{
c = path.Last();
if (c != FTP_MVS_DOUBLE_QUOTE && c != '\'')
break;
else
path.RemoveLast();
}
while (path.Replace(_T(".."), _T(".")));
int pos = path.Find(_T("."));
while (pos != -1)
{
m_Segments.push_back(path.Left(pos));
path = path.Mid(pos + 1);
pos = path.Find( _T(".") );
}
if (path != _T(""))
m_Segments.push_back(path);
else
m_prefix = _T(".");
if (isFile)
{
if (m_prefix == _T("."))
return false;
if (m_Segments.empty())
return false;
file = m_Segments.back();
m_Segments.pop_back();
int pos = file.Find('(');
int pos2 = file.Find(')');
if (pos != -1)
{
if (!pos || pos2 <= pos || pos2 != (int)file.Length() - 2)
return false;
m_Segments.push_back(file.Left(pos));
file = file.Mid(pos + 1, pos2 - pos - 1);
m_prefix = _T("");
}
else if (pos2 != -1)
return false;
else
m_prefix = _T(".");
}
}
break;
case VXWORKS:
{
int colon2;
if (path[0] != ':' || (colon2 = path.Mid(1).Find(':')) < 1)
{
m_bEmpty = true;
return false;
}
int slash = path.Find('/');
if (slash != -1 && slash <= colon2)
{
m_bEmpty = true;
return false;
}
m_prefix = path.Left(colon2 + 2);
path = path.Mid(colon2 + 1);
goto set_path_default;
}
break;
case DOS:
// Check for starting drive letter
path.Replace(_T("\\"), _T("/"));
pos = path.Find('/');
if (pos != 2 || path.c_str()[1] != ':' ||
!((path.c_str()[0] >= 'A' && path.c_str()[0] <= 'Z') || (path.c_str()[0] >= 'a' && path.c_str()[0] <= 'z')))
{
m_bEmpty = true;
return false;
}
// No break on purpose!
default:
set_path_default:
while (path.Replace(_T("//"), _T("/")));
if (path.c_str()[0] == '/')
path.Remove(0, 1);
if (isFile)
{
pos = path.Find('/', true);
if (pos == -1 || static_cast<size_t>(pos) == (path.Length() - 1))
{
m_bEmpty = true;
return false;
}
file = path.Mid(pos + 1);
path = path.Left(pos + 1);
if (file == _T(".") || file == _T(".."))
{
m_bEmpty = true;
return false;
}
}
else if (path != _T("") && path.Right(1) != _T("/"))
path = path + _T("/");
pos = path.Find(_T("/"));
while (pos != -1)
{
wxString segment = path.Left(pos);
if (segment == _T(".."))
{
if (m_Segments.empty())
{
m_bEmpty = true;
return false;
}
m_Segments.pop_back();
}
else if (segment != _T("."))
m_Segments.push_back(segment);
path = path.Mid(pos + 1);
pos = path.Find(_T("/"));
}
break;
}
if (isFile)
newPath = file;
return true;
}
wxString CServerPath::GetPath() const
{
if (m_bEmpty)
return _T("");
wxString path;
switch (m_type)
{
case VMS:
{
path = m_prefix + _T("[");
for (tConstSegmentIter iter = m_Segments.begin(); iter != m_Segments.end(); iter++)
path += *iter + _T(".");
path.RemoveLast();
path += _T("]");
}
break;
case DOS:
{
for (tConstSegmentIter iter = m_Segments.begin(); iter != m_Segments.end(); iter++)
path += *iter + _T("\\");
}
break;
case MVS:
path = _T("'");
for (tConstSegmentIter iter = m_Segments.begin(); iter != m_Segments.end(); iter++)
{
if (iter != m_Segments.begin())
path += _T(".");
path += *iter;
}
path += m_prefix + _T("'");
break;
case VXWORKS:
path = m_prefix;
for (tConstSegmentIter iter = m_Segments.begin(); iter != m_Segments.end(); iter++)
{
if (iter != m_Segments.begin())
path += _T("/");
path += *iter;
}
break;
default:
path = _T("/");
for (tConstSegmentIter iter = m_Segments.begin(); iter != m_Segments.end(); iter++)
path += *iter + _T("/");
break;
}
return path;
}
bool CServerPath::HasParent() const
{
if (m_bEmpty)
return false;
if (m_type == DOS || m_type == VMS || m_type == MVS)
return m_Segments.size() > 1;
return !m_Segments.empty();
}
CServerPath CServerPath::GetParent() const
{
if (!HasParent())
return CServerPath();
CServerPath parent = *this;
parent.m_Segments.pop_back();
if (m_type == MVS)
parent.m_prefix = _T(".");
return parent;
}
wxString CServerPath::GetLastSegment() const
{
if (!HasParent())
return _T("");
if (!m_Segments.empty())
return m_Segments.back();
else
return _T("");
}
wxString CServerPath::GetSafePath() const
{
if (m_bEmpty)
return _T("");
wxString safepath;
safepath.Printf(_T("%d %d "), m_type, m_prefix.Length());
if (m_prefix != _T(""))
safepath += m_prefix + _T(" ");
for (tConstSegmentIter iter = m_Segments.begin(); iter != m_Segments.end(); iter++)
safepath += wxString::Format(_T("%d %s "), iter->Length(), iter->c_str());
if (!m_Segments.empty())
safepath.RemoveLast();
return safepath;
}
bool CServerPath::SetSafePath(wxString path)
{
m_bEmpty = true;
m_prefix = _T("");
m_Segments.clear();
int pos = path.Find(' ');
if (pos < 1)
return false;
long type;
if (!path.Left(pos).ToLong(&type))
return false;
m_type = (ServerType)type;
path = path.Mid(pos + 1);
pos = path.Find(' ');
if (pos == -1)
{
if (path != _T("0"))
return false;
else
{
// Is root folder, like / on unix like systems.
m_bEmpty = false;
return true;
}
}
if (pos < 1)
return false;
unsigned long len;
if (!path.Left(pos).ToULong(&len))
return false;
path = path.Mid(pos + 1);
if (path.Length() < len)
return false;
if (len)
{
m_prefix = path.Left(len);
path = path.Mid(len);
}
while (path != _T(""))
{
pos = path.Find(' ');
if (pos < 1)
return false;
if (!path.Left(pos).ToULong(&len))
return false;
path = path.Mid(pos + 1);
if (path.Length() < len)
return false;
if (!len)
return false;
if (path.Length() < len)
return false;
m_Segments.push_back(path.Left(len));
path = path.Mid(len + 1);
}
m_bEmpty = false;
return true;
}
bool CServerPath::SetType(enum ServerType type)
{
if (!m_bEmpty && m_type != DEFAULT)
return false;
m_type = type;
return true;
}
enum ServerType CServerPath::GetType() const
{
return m_type;
}
bool CServerPath::IsSubdirOf(const CServerPath &path, bool cmpNoCase) const
{
if (m_bEmpty || path.m_bEmpty)
return false;
if (cmpNoCase && m_prefix.CmpNoCase(path.m_prefix))
return false;
if (!cmpNoCase && m_prefix != path.m_prefix)
return false;
if (m_type != path.m_type)
return false;
if (!HasParent())
return false;
tConstSegmentIter iter1 = m_Segments.begin();
tConstSegmentIter iter2 = path.m_Segments.begin();
while (iter1 != m_Segments.end())
{
if (iter2 == path.m_Segments.end())
return true;
if (cmpNoCase)
{
if (iter1->CmpNoCase(*iter2))
return false;
}
else if (*iter1 != *iter2)
return false;
iter1++;
iter2++;
}
return false;
}
bool CServerPath::IsParentOf(const CServerPath &path, bool cmpNoCase) const
{
if (!this)
return false;
return path.IsSubdirOf(*this, cmpNoCase);
}
bool CServerPath::ChangePath(wxString subdir)
{
wxString subdir2 = subdir;
return ChangePath(subdir2, false);
}
bool CServerPath::ChangePath(wxString &subdir, bool isFile)
{
wxString dir = subdir;
wxString file;
dir.Trim(true);
dir.Trim(false);
if (dir == _T(""))
{
if (IsEmpty() || isFile)
return false;
else
return true;
}
switch (m_type)
{
case VMS:
{
int pos1 = subdir.Find(_T("["));
if (pos1 == -1)
{
int pos2 = dir.Find(']', true);
if (pos2 != -1)
return false;
if (isFile)
{
if (IsEmpty())
return false;
subdir = dir;
return true;
}
while (dir.Replace(_T(".."), _T(".")));
}
else
{
int pos2 = dir.Find(']', true);
if (pos2 == -1)
return false;
if (isFile && static_cast<size_t>(pos2) == (dir.Length() - 1))
return false;
if (isFile && static_cast<size_t>(pos2) != (dir.Length() - 1))
return false;
if (pos2 <= pos1)
return false;
if (isFile)
file = dir.Mid(pos2 + 1);
dir = dir.Left(pos2);
if (pos1)
m_prefix = dir.Left(pos1);
else
m_prefix = _T("");
dir = dir.Mid(pos1 + 1);
m_Segments.clear();
}
int pos = dir.Find(_T("."));
while (pos != -1)
{
m_Segments.push_back(dir.Left(pos));
dir = dir.Mid(pos + 1);
pos = dir.Find(_T("."));
}
if (dir != _T(""))
m_Segments.push_back(dir);
}
break;
case DOS:
{
dir.Replace(_T("\\"), _T("/"));
while (dir.Replace(_T("//"), _T("/")));
if (dir.Length() >= 2 && dir.c_str()[1] == ':')
m_Segments.clear();
else if (dir.Left(1) == _T("/"))
{
if (m_Segments.empty())
{
Clear();
return false;
}
wxString first = m_Segments.front();
m_Segments.clear();
m_Segments.push_back(first);
dir = dir.Mid(1);
}
if (isFile)
{
int pos = dir.Find('/', true);
if (pos == (int)dir.Length() - 1)
{
Clear();
return false;
}
if (pos == -1)
{
subdir = dir;
return true;
}
else
{
file = dir.Mid(pos + 1);
dir = dir.Left(pos + 1);
}
}
else if (dir != _T("") && dir.Right(1) != _T("/"))
dir += _T("/");
int pos = dir.Find(_T("/"));
while (pos != -1)
{
wxString segment = dir.Left(pos);
if (segment == _T(".."))
{
if (m_Segments.size() <= 1)
{
Clear();
return false;
}
m_Segments.pop_back();
}
else if (segment != _T("."))
m_Segments.push_back(segment);
dir = dir.Mid(pos + 1);
pos = dir.Find(_T("/"));
}
}
break;
case MVS:
{
int i = 0;
wxChar c = subdir.c_str()[i];
while (c == FTP_MVS_DOUBLE_QUOTE)
c = subdir.c_str()[++i];
subdir.Remove(0, i);
while (subdir != _T(""))
{
c = subdir.Last();
if (c != FTP_MVS_DOUBLE_QUOTE)
break;
else
subdir.RemoveLast();
}
}
if (subdir == _T(""))
return false;
while (subdir.Replace(_T(".."), _T(".")));
if (subdir.c_str()[0] == '\'')
{
if (subdir.Last() != '\'')
return false;
if (SetPath(subdir, isFile))
file = subdir;
else
return false;
}
else if (subdir.Last() == '\'')
return false;
else if (!IsEmpty())
{
if (m_prefix != _T("."))
return false;
if (subdir.c_str()[0] == '.')
subdir.Remove(0, 1);
int pos = subdir.Find('.');
while (pos != -1)
{
m_Segments.push_back(subdir.Left(pos));
subdir = subdir.Mid(pos + 1);
}
if (subdir != _T(""))
{
m_Segments.push_back(subdir);
m_prefix = _T("");
}
else
m_prefix = _T(".");
if (isFile)
{
if (m_prefix == _T("."))
return false;
if (m_Segments.empty())
return false;
file = m_Segments.back();
m_Segments.pop_back();
int pos = file.Find('(');
int pos2 = file.Find(')');
if (pos != -1)
{
if (!pos || pos2 <= pos || pos2 != (int)file.Length() - 2)
return false;
m_Segments.push_back(file.Left(pos));
file = file.Mid(pos + 1, pos2 - pos - 1);
}
else if (pos2 != -1)
return false;
else
m_prefix = _T(".");
}
}
else if (SetPath(subdir, isFile))
file = subdir;
else
return false;
break;
case VXWORKS:
{
if (dir[0] != ':')
{
if (IsEmpty())
return false;
}
else
{
int colon2;
if ((colon2 = dir.Mid(1).Find(':')) < 1)
return false;
int slash = dir.Find('/');
if (slash != -1 && slash <= colon2)
return false;
m_prefix = dir.Left(colon2 + 2);
dir = dir.Mid(colon2 + 1);
if (dir[0] == '/')
return false;
m_Segments.clear();
}
if (isFile && dir.Find('/') == -1)
return false;
}
// No break on purpose
default:
{
while (dir.Replace(_T("//"), _T("/")));
if (dir.c_str()[0] == '/')
{
m_prefix = _T("");
m_Segments.clear();
dir = dir.Mid(1);
}
if (isFile)
{
int pos = dir.Find('/', true);
if (pos == (int)dir.Length() - 1)
{
Clear();
return false;
}
if (pos == -1)
{
subdir = dir;
return true;
}
else
{
file = dir.Mid(pos + 1);
dir = dir.Left(pos + 1);
}
}
else if (dir != _T("") && dir.Right(1) != _T("/"))
dir += _T("/");
int pos = dir.Find(_T("/"));
while (pos != -1)
{
wxString segment = dir.Left(pos);
if (segment == _T(".."))
{
if (m_Segments.empty())
{
Clear();
return false;
}
m_Segments.pop_back();
}
else if (segment != _T("."))
m_Segments.push_back(segment);
dir = dir.Mid(pos + 1);
pos = dir.Find(_T("/"));
}
}
break;
}
if (isFile)
subdir = file;
m_bEmpty = false;
return true;
}
bool CServerPath::operator==(const CServerPath &op) const
{
if (m_bEmpty != op.m_bEmpty)
return false;
else if (m_prefix != op.m_prefix)
return false;
else if (m_type != op.m_type)
return false;
else if (m_Segments != op.m_Segments)
return false;
return true;
}
bool CServerPath::operator!=(const CServerPath &op) const
{
if (!this)
return false;
return !(*this == op);
}
wxString CServerPath::FormatFilename(const wxString &filename, bool omitPath /*=false*/) const
{
if (m_bEmpty)
return filename;
if (filename == _T(""))
return _T("");
wxString fullpath;
tConstSegmentIter iter;
switch (m_type)
{
case MVS:
if (m_prefix == _T(".") && omitPath)
return filename;
fullpath = _T("'");
for (iter = m_Segments.begin(); iter != m_Segments.end(); iter++)
fullpath += *iter + _T(".");
if (m_prefix != _T("."))
{
if (fullpath.Last() == '.')
fullpath.RemoveLast();
fullpath += _T("(") + filename + _T(")");
}
else
fullpath += filename;
fullpath += _T("'");
break;
case VXWORKS:
if (omitPath)
fullpath = filename;
else
fullpath = GetPath() + _T("/") + filename;
break;
default:
if (omitPath)
fullpath = filename;
else
fullpath = GetPath() + filename;
}
return fullpath;
}
int CServerPath::CmpNoCase(const CServerPath &op) const
{
if (m_bEmpty != op.m_bEmpty)
return 1;
else if (m_prefix != op.m_prefix)
return 1;
else if (m_type != op.m_type)
return 1;
if (m_Segments.size() > op.m_Segments.size())
return 1;
else if (m_Segments.size() < op.m_Segments.size())
return -1;
tConstSegmentIter iter = m_Segments.begin();
tConstSegmentIter iter2 = op.m_Segments.begin();
while (iter != m_Segments.end())
{
int res = iter++->CmpNoCase(*iter2++);
if (res)
return res;
}
return 0;
}
bool CServerPath::AddSegment(const wxString& segment)
{
if (IsEmpty())
return false;
// TODO: Check for invalid characters
m_Segments.push_back(segment);
return true;
}
CServerPath CServerPath::GetCommonParent(const CServerPath& path) const
{
if (m_bEmpty || path.m_bEmpty)
return CServerPath();
if (m_type != path.m_type ||
m_prefix != path.m_prefix)
return CServerPath();
if (!HasParent() || !path.HasParent())
return CServerPath();
CServerPath parent;
parent.m_bEmpty = false;
parent.m_type = m_type;
parent.m_prefix = m_prefix;
std::list<wxString>::const_iterator iter = m_Segments.begin();
std::list<wxString>::const_iterator iter2 = path.m_Segments.begin();
while (iter != m_Segments.end() && iter2 != path.m_Segments.end())
{
if (*iter != *iter2)
return parent;
parent.m_Segments.push_back(*iter);
iter++;
iter2++;
}
return parent;
}
syntax highlighted by Code2HTML, v. 0.9.1