You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
421 lines
12 KiB
421 lines
12 KiB
/***************************************************************************
|
|
* Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
***************************************************************************/
|
|
#include "purl.h"
|
|
|
|
#include <tqfileinfo.h>
|
|
#include <tqdatetime.h>
|
|
#include <tqdir.h>
|
|
#include <tqregexp.h>
|
|
#include <tqmap.h>
|
|
# include <tqnetwork.h>
|
|
|
|
#include "common/common/synchronous.h"
|
|
#include "process.h"
|
|
|
|
#if !defined(NO_KDE)
|
|
# include <kio/netaccess.h>
|
|
# include <kfileitem.h>
|
|
# include <kconfigbackend.h>
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
PURL::Http::Http(const TQString &hostname)
|
|
: TQHttp(hostname)
|
|
{
|
|
connect(this, TQT_SIGNAL(responseHeaderReceived(const TQHttpResponseHeader &)),
|
|
TQT_SLOT(responseHeaderReceivedSlot(const TQHttpResponseHeader &)));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
class PURL::Private
|
|
{
|
|
public:
|
|
TQString convertWindowsFilepath(const TQString &filepath);
|
|
|
|
private:
|
|
TQMap<char, TQString> _winDrives; // drive -> unix path
|
|
TQMap<TQString, TQString> _winPaths; // windows path -> unix path
|
|
|
|
TQString getWindowsDrivePath(char drive);
|
|
bool checkCachedPath(TQString &filepath) const;
|
|
TQString cachePath(const TQString &origin, const TQString &filepath);
|
|
TQString convertWindowsShortFilepath(const TQString &filepath);
|
|
TQString findName(const TQString &path, const TQString &name);
|
|
static TQString findName(const TQString &filepath);
|
|
};
|
|
|
|
TQString PURL::Private::getWindowsDrivePath(char drive)
|
|
{
|
|
#if defined(Q_OS_UNIX)
|
|
if ( !_winDrives.contains(drive) ) {
|
|
TQStringList args;
|
|
args += "-u";
|
|
TQString s;
|
|
s += drive;
|
|
args += s + ":\\";
|
|
::Process::StringOutput process;
|
|
process.setup("winepath", args, false);
|
|
::Process::State state = ::Process::runSynchronously(process, ::Process::Start, 3000);
|
|
if ( state!=::Process::Exited ) qWarning("Error running \"winepath\" with \"%s\" (%i)", args.join(" ").latin1(), state);
|
|
s = process.sout() + process.serr();
|
|
TQDir dir(s.stripWhiteSpace());
|
|
_winDrives[drive] = dir.canonicalPath();
|
|
}
|
|
return _winDrives[drive];
|
|
#else
|
|
return TQString("%1:\\").tqarg(drive);
|
|
#endif
|
|
}
|
|
|
|
bool PURL::Private::checkCachedPath(TQString &filepath) const
|
|
{
|
|
if ( !_winPaths.contains(filepath) ) return false;
|
|
filepath = _winPaths[filepath];
|
|
return true;
|
|
}
|
|
|
|
TQString PURL::Private::cachePath(const TQString &origin, const TQString &filepath)
|
|
{
|
|
_winPaths[origin] = filepath;
|
|
return filepath;
|
|
}
|
|
|
|
TQString PURL::Private::convertWindowsFilepath(const TQString &filepath)
|
|
{
|
|
// appears to be an absolute windows path
|
|
if ( filepath[0]=='\\' ) {
|
|
TQString tmp = filepath;
|
|
if ( checkCachedPath(tmp) ) return tmp;
|
|
return cachePath(filepath, convertWindowsShortFilepath(tmp.replace('\\', "/")));
|
|
}
|
|
// appears to be a windows path with a drive
|
|
if ( (filepath.length()>=2 && filepath[0].isLetter() && filepath[1]==':') ) {
|
|
TQString tmp = filepath;
|
|
if ( checkCachedPath(tmp) ) return tmp;
|
|
tmp = getWindowsDrivePath(filepath[0]) + tmp.mid(2).replace('\\', "/");
|
|
return cachePath(filepath, convertWindowsShortFilepath(tmp));
|
|
}
|
|
return filepath;
|
|
}
|
|
|
|
TQString PURL::Private::findName(const TQString &path, const TQString &name)
|
|
{
|
|
TQString filepath = path + '/' + name;
|
|
if ( checkCachedPath(filepath) ) return filepath;
|
|
return cachePath(filepath, findName(filepath));
|
|
}
|
|
|
|
TQString PURL::Private::findName(const TQString &filepath)
|
|
{
|
|
TQFileInfo finfo(filepath);
|
|
if ( finfo.exists() || !finfo.dir().exists() ) return finfo.filePath();
|
|
TQStringList list = finfo.dir().entryList(TQDir::All, TQDir::Name);
|
|
// find if name is just in a different case
|
|
for (uint j=0; j<uint(list.count()); j++) {
|
|
if ( list[j].lower()!=finfo.fileName().lower() ) continue;
|
|
return finfo.dirPath() + '/' + list[j];
|
|
}
|
|
// find if name is a shorted filename
|
|
TQRegExp rexp("([^~]+)~(\\d+).*");
|
|
if ( !rexp.exactMatch(finfo.fileName()) ) return finfo.filePath();
|
|
TQString start = rexp.cap(1).lower();
|
|
uint index = rexp.cap(2).toUInt();
|
|
uint k = 0;
|
|
for (uint j = 0; j<uint(list.count()); j++) {
|
|
if ( !list[j].lower().startsWith(start) ) continue;
|
|
k++;
|
|
if ( k==index ) return finfo.dirPath() + '/' + list[j];
|
|
}
|
|
return finfo.filePath();
|
|
}
|
|
|
|
TQString PURL::Private::convertWindowsShortFilepath(const TQString &filepath)
|
|
{
|
|
// apparently "winepath" cannot do that for us and it is a real pain too...
|
|
// we assume filepath is an absolute unix path
|
|
// first see if we know the dirpath
|
|
TQFileInfo finfo(filepath);
|
|
TQString path = finfo.dirPath();
|
|
if ( checkCachedPath(path) ) return findName(path, finfo.fileName());
|
|
|
|
// otherwise go down the path
|
|
TQStringList names = TQStringList::split('/', filepath);
|
|
TQString tmp;
|
|
for (uint i=0; i<uint(names.count()); i++)
|
|
tmp = findName(tmp, names[i]);
|
|
if ( filepath.endsWith("/") ) tmp += "/";
|
|
return tmp;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
PURL::Private *PURL::Base::_private = 0;
|
|
|
|
PURL::Base::Base(const TQString &filepath)
|
|
: _relative(true)
|
|
{
|
|
if ( !filepath.isEmpty() ) {
|
|
if ( _private==0 ) _private = new Private;
|
|
#if defined(Q_OS_UNIX)
|
|
TQString tmp = _private->convertWindowsFilepath(filepath);
|
|
#else
|
|
TQString tmp = filepath;
|
|
#endif
|
|
if ( tmp.startsWith("~") ) tmp = TQDir::homeDirPath() + tmp.mid(1);
|
|
_relative = Q3Url::isRelativeUrl(tmp);
|
|
#if defined(Q_OS_UNIX)
|
|
if ( !tmp.startsWith("/") ) tmp = '/' + tmp;
|
|
#endif
|
|
#if defined(NO_KDE)
|
|
_url.setPath(tmp);
|
|
#else
|
|
_url = KURL::fromPathOrURL(tmp);
|
|
#endif
|
|
_url.cleanPath();
|
|
}
|
|
}
|
|
|
|
PURL::Base::Base(const KURL &url)
|
|
: _relative(false), _url(url)
|
|
{
|
|
_url.cleanPath();
|
|
}
|
|
|
|
bool PURL::Base::isLocal() const
|
|
{
|
|
return ( _url.protocol().isEmpty() || _url.protocol()=="file" );
|
|
}
|
|
|
|
bool PURL::Base::operator ==(const Base &url) const
|
|
{
|
|
if ( _url.isEmpty() ) return url._url.isEmpty();
|
|
return _url==url._url;
|
|
}
|
|
|
|
TQString PURL::Base::path(SeparatorType type) const
|
|
{
|
|
#if defined(NO_KDE)
|
|
TQString s = _url.dirPath();
|
|
if ( !s.isEmpty() && !s.endsWith("/") ) s += '/';
|
|
#else
|
|
TQString s = _url.directory(false, false);
|
|
#endif
|
|
if ( type==WindowsSeparator ) {
|
|
for (uint i=0; i<uint(s.length()); i++)
|
|
if ( s[i]=='/' ) s[i] = '\\';
|
|
}
|
|
return s;
|
|
}
|
|
|
|
TQString PURL::Base::unterminatedPath(SeparatorType type) const
|
|
{
|
|
#if defined(NO_KDE)
|
|
TQString s = _url.dirPath();
|
|
if ( s.endsWith("/") ) s = s.mid(0, s.length()-1);
|
|
#else
|
|
TQString s = _url.directory(true, false);
|
|
#endif
|
|
if ( type==WindowsSeparator ) {
|
|
for (uint i=0; i<uint(s.length()); i++)
|
|
if ( s[i]=='/' ) s[i] = '\\';
|
|
}
|
|
return s;
|
|
}
|
|
|
|
TQString PURL::Base::pretty() const
|
|
{
|
|
#if defined(NO_KDE)
|
|
TQString s = _url.toString();
|
|
if ( s.startsWith("://") ) return s.mid(3);
|
|
return s;
|
|
#else
|
|
return _url.prettyURL(0, KURL::StripFileProtocol);
|
|
#endif
|
|
}
|
|
|
|
PURL::Directory PURL::Base::directory() const
|
|
{
|
|
return Directory(path());
|
|
}
|
|
|
|
bool PURL::Base::isInto(const Directory &dir) const
|
|
{
|
|
return path().startsWith(dir.path());
|
|
}
|
|
|
|
bool PURL::Base::httpUrlExists(bool *ok) const
|
|
{
|
|
qInitNetworkProtocols();
|
|
if (ok) *ok = false;
|
|
Http http(_url.host());
|
|
Synchronous sync(500);
|
|
TQObject::connect(&http, TQT_SIGNAL(done(bool)), &sync, TQT_SLOT(done()));
|
|
TQFileInfo info(_url.fileName(false));
|
|
http.head(_url.path());
|
|
if ( !sync.enterLoop() ) return false; // timeout
|
|
if ( http.error()!=TQHttp::NoError ) return false;
|
|
if (ok ) *ok = true;
|
|
return ( http._header.statusCode()==200 );
|
|
}
|
|
|
|
bool PURL::Base::exists(TQDateTime *lastModified) const
|
|
{
|
|
if ( isEmpty() ) return false;
|
|
if ( isLocal() ) {
|
|
TQFileInfo fi(_url.path());
|
|
if (lastModified) *lastModified = fi.lastModified();
|
|
return fi.exists();
|
|
}
|
|
if ( _url.protocol()=="http" ) return httpUrlExists();
|
|
#if !defined(NO_KDE)
|
|
if (lastModified) {
|
|
KIO::UDSEntry uds;
|
|
if ( !KIO::NetAccess::stat(_url, uds, tqApp->mainWidget()) ) return false;
|
|
KFileItem item(uds, _url);
|
|
lastModified->setTime_t(item.time(KIO::UDS_MODIFICATION_TIME));
|
|
return true;
|
|
} else {
|
|
// assume file exists if ioslave cannot tell...
|
|
return KIO::NetAccess::exists(_url, true, tqApp->mainWidget());
|
|
}
|
|
#else
|
|
if (lastModified) lastModified->setTime_t(0);
|
|
// assume file exists
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
PURL::Url PURL::Url::fromPathOrUrl(const TQString &s)
|
|
{
|
|
KURL kurl = KURL::fromPathOrURL(s);
|
|
if ( !kurl.protocol().isEmpty() && kurl.protocol()!="file" && kurl.protocol().length()!=1 ) return kurl;
|
|
return Url(s.startsWith("file://") ? s.mid(7) : s);
|
|
}
|
|
|
|
PURL::Url::Url(const Directory &dir, const TQString &filename, FileType type)
|
|
: Base(dir.path() + '/' + addExtension(filename, type))
|
|
{}
|
|
|
|
PURL::Url::Url(const Directory &dir, const TQString &filepath)
|
|
: Base(dir.path() + '/' + filepath)
|
|
{}
|
|
|
|
PURL::FileType PURL::Url::fileType() const
|
|
{
|
|
TQFileInfo info(filename());
|
|
FOR_EACH(FileType, type)
|
|
for (uint i=0; type.data().extensions[i]; i++)
|
|
if ( info.extension(false).lower()==type.data().extensions[i] ) return type;
|
|
return Unknown;
|
|
}
|
|
|
|
TQString PURL::Url::basename() const
|
|
{
|
|
TQFileInfo info(_url.fileName(false));
|
|
return info.baseName(true);
|
|
}
|
|
|
|
TQString PURL::Url::filename() const
|
|
{
|
|
TQFileInfo info(_url.fileName(false));
|
|
return info.fileName();
|
|
}
|
|
|
|
TQString PURL::Url::filepath(SeparatorType type) const
|
|
{
|
|
return path(type) + filename();
|
|
}
|
|
|
|
PURL::Url PURL::Url::toExtension(const TQString &extension) const
|
|
{
|
|
TQFileInfo info(filename());
|
|
return Url(directory().path() + info.baseName(true) + '.' + extension);
|
|
}
|
|
|
|
PURL::Url PURL::Url::appendExtension(const TQString &extension) const
|
|
{
|
|
TQFileInfo info(filename());
|
|
return Url(directory().path() + info.fileName() + '.' + extension);
|
|
}
|
|
|
|
TQString PURL::Url::relativeTo(const Directory &dir, SeparatorType type) const
|
|
{
|
|
TQString s = filepath(type);
|
|
if ( !isInto(dir) ) return s;
|
|
return s.right(s.length() - dir.path(type).length());
|
|
}
|
|
|
|
PURL::Url PURL::Url::toAbsolute(const Directory &dir) const
|
|
{
|
|
if ( isRelative() ) return Url(dir, filepath());
|
|
return *this;
|
|
}
|
|
|
|
bool PURL::findExistingUrl(Url &url)
|
|
{
|
|
if ( url.exists() ) return true;
|
|
TQFileInfo info(url.filename());
|
|
Url tmp = url.toExtension(info.extension(false).upper());
|
|
if ( !tmp.exists() ) {
|
|
tmp = url.toExtension(info.extension(false).lower());
|
|
if ( !tmp.exists() ) return false;
|
|
}
|
|
url = tmp;
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#if !defined(NO_KDE)
|
|
PURL::UrlList::UrlList(const KURL::List &list)
|
|
{
|
|
KURL::List::const_iterator it;
|
|
for (it=list.begin(); it!=list.end(); ++it) append(*it);
|
|
}
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
PURL::Directory::Directory(const TQString &path)
|
|
: Base(path.isEmpty() ? TQString() : path + '/')
|
|
{}
|
|
|
|
PURL::Directory PURL::Directory::up() const
|
|
{
|
|
TQDir dir(path());
|
|
dir.cdUp();
|
|
return PURL::Directory(dir.path());
|
|
}
|
|
|
|
PURL::Directory PURL::Directory::down(const TQString &subPath) const
|
|
{
|
|
Q_ASSERT( TQDir::isRelativePath(subPath) );
|
|
TQDir dir(path());
|
|
dir.cd(subPath);
|
|
return PURL::Directory(dir.path());
|
|
}
|
|
|
|
TQStringList PURL::Directory::files(const TQString &filter) const
|
|
{
|
|
TQDir dir(path());
|
|
return dir.entryList(filter, TQDir::Files);
|
|
}
|
|
|
|
PURL::Url PURL::Directory::findMatchingFilename(const TQString &filename) const
|
|
{
|
|
TQDir dir(path());
|
|
TQStringList files = dir.entryList(TQDir::Files);
|
|
for (uint i=0; i<uint(files.count()); i++)
|
|
if ( files[i].lower()==filename.lower() ) return Url(*this, files[i]);
|
|
return Url(*this, filename);
|
|
}
|
|
|
|
PURL::Directory PURL::Directory::current()
|
|
{
|
|
return TQDir::currentDirPath();
|
|
}
|