lyx_mirror/src/support/FileName.cpp

1011 lines
22 KiB
C++
Raw Normal View History

/**
Rename files in src/support, step one. src/support/package.h src/support/Package.h Package src/support/package.C.in src/support/Package.C.in Package src/support/path.h src/support/Path.h Path src/support/fs_extras.h src/support/fs_extras.h NOCLASSES src/support/RandomAccessList.h src/support/RandomAccessList.h RandomAccessList src/support/lyxmanip.h src/support/lyxmanip.h NOCLASSES src/support/rename.C src/support/rename.cpp NOCLASSES src/support/abort.C src/support/abort.cpp NOCLASSES src/support/lyxlib.h src/support/lyxlib.h NOCLASSES src/support/ExceptionMessage.h src/support/ExceptionMessage.h ExceptionMessage src/support/copy.C src/support/copy.cpp NOCLASSES src/support/limited_stack.h src/support/limited_stack.h limited_stack src/support/filefilterlist.C src/support/FileFilterList.cpp ['FileFilterList', 'Filter'] src/support/cow_ptr.h src/support/cow_ptr.h cow_ptr src/support/os_unix.C src/support/os_unix.cpp NOCLASSES src/support/socktools.h src/support/socktools.h NOCLASSES src/support/forkedcontr.h src/support/ForkedcallsController.h ForkedcallsController src/support/os.h src/support/os.h NOCLASSES src/support/FileMonitor.h src/support/FileMonitor.h FileMonitor src/support/copied_ptr.h src/support/copied_ptr.h copied_ptr src/support/translator.h src/support/Translator.h Translator src/support/filetools.C src/support/filetools.cpp NOCLASSES src/support/unlink.C src/support/unlink.cpp NOCLASSES src/support/os_win32.C src/support/os_win32.cpp GetFolderPath src/support/lstrings.C src/support/lstrings.cpp NOCLASSES src/support/qstring_helpers.C src/support/qstring_helpers.cpp NOCLASSES src/support/getcwd.C src/support/getcwd.cpp NOCLASSES src/support/systemcall.C src/support/Systemcall.cpp Systemcall src/support/lyxalgo.h src/support/lyxalgo.h NOCLASSES src/support/filefilterlist.h src/support/FileFilterList.h ['FileFilterList', 'Filter'] src/support/unicode.C src/support/unicode.cpp IconvProcessor src/support/userinfo.C src/support/userinfo.cpp NOCLASSES src/support/lyxtime.C src/support/lyxtime.cpp NOCLASSES src/support/kill.C src/support/kill.cpp NOCLASSES src/support/docstring.C src/support/docstring.cpp to_local8bit_failure src/support/os_cygwin.C src/support/os_cygwin.cpp NOCLASSES src/support/lyxsum.C src/support/lyxsum.cpp NOCLASSES src/support/environment.C src/support/environment.cpp NOCLASSES src/support/filetools.h src/support/filetools.h NOCLASSES src/support/textutils.C src/support/textutils.cpp NOCLASSES src/support/mkdir.C src/support/mkdir.cpp NOCLASSES src/support/forkedcall.C src/support/Forkedcall.cpp ['ForkedProcess', 'Forkedcall'] src/support/tempname.C src/support/tempname.cpp NOCLASSES src/support/os_win32.h src/support/os_win32.h GetFolderPath src/support/types.h src/support/types.h NOCLASSES src/support/lstrings.h src/support/lstrings.h NOCLASSES src/support/forkedcallqueue.C src/support/ForkedCallQueue.cpp ForkedCallQueue src/support/qstring_helpers.h src/support/qstring_helpers.h NOCLASSES src/support/convert.C src/support/convert.cpp NOCLASSES src/support/filename.C src/support/FileName.cpp ['FileName', 'DocFileName'] src/support/tests/convert.C src/support/tests/convert.cpp NOCLASSES src/support/tests/filetools.C src/support/tests/filetools.cpp NOCLASSES src/support/tests/lstrings.C src/support/tests/lstrings.cpp NOCLASSES src/support/tests/boost.C src/support/tests/boost.cpp NOCLASSES src/support/docstream.C src/support/docstream.cpp ['iconv_codecvt_facet_exception', 'idocfstream', 'odocfstream'] src/support/std_istream.h src/support/std_istream.h NOCLASSES src/support/systemcall.h src/support/Systemcall.h Systemcall src/support/chdir.C src/support/chdir.cpp NOCLASSES src/support/std_ostream.h src/support/std_ostream.h NOCLASSES src/support/unicode.h src/support/unicode.h IconvProcessor src/support/path.C src/support/Path.cpp Path src/support/fs_extras.C src/support/fs_extras.cpp NOCLASSES src/support/userinfo.h src/support/userinfo.h NOCLASSES src/support/lyxtime.h src/support/lyxtime.h NOCLASSES src/support/docstring.h src/support/docstring.h to_local8bit_failure src/support/debugstream.h src/support/debugstream.h basic_debugstream src/support/environment.h src/support/environment.h NOCLASSES src/support/textutils.h src/support/textutils.h NOCLASSES src/support/forkedcall.h src/support/Forkedcall.h ['ForkedProcess', 'Forkedcall'] src/support/socktools.C src/support/socktools.cpp NOCLASSES src/support/forkedcallqueue.h src/support/ForkedCallQueue.h ForkedCallQueue src/support/forkedcontr.C src/support/ForkedcallsController.cpp ForkedcallsController src/support/os.C src/support/os.cpp NOCLASSES src/support/convert.h src/support/convert.h NOCLASSES src/support/filename.h src/support/FileName.h ['FileName', 'DocFileName'] src/support/docstream.h src/support/docstream.h ['iconv_codecvt_facet_exception', 'idocfstream', 'odocfstream'] src/support/FileMonitor.C src/support/FileMonitor.cpp FileMonitor git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@18024 a592a061-630c-0410-9148-cb99ea01b6c8
2007-04-26 05:12:52 +00:00
* \file FileName.cpp
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Angus Leeming
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
Rename files in src/support, step one. src/support/package.h src/support/Package.h Package src/support/package.C.in src/support/Package.C.in Package src/support/path.h src/support/Path.h Path src/support/fs_extras.h src/support/fs_extras.h NOCLASSES src/support/RandomAccessList.h src/support/RandomAccessList.h RandomAccessList src/support/lyxmanip.h src/support/lyxmanip.h NOCLASSES src/support/rename.C src/support/rename.cpp NOCLASSES src/support/abort.C src/support/abort.cpp NOCLASSES src/support/lyxlib.h src/support/lyxlib.h NOCLASSES src/support/ExceptionMessage.h src/support/ExceptionMessage.h ExceptionMessage src/support/copy.C src/support/copy.cpp NOCLASSES src/support/limited_stack.h src/support/limited_stack.h limited_stack src/support/filefilterlist.C src/support/FileFilterList.cpp ['FileFilterList', 'Filter'] src/support/cow_ptr.h src/support/cow_ptr.h cow_ptr src/support/os_unix.C src/support/os_unix.cpp NOCLASSES src/support/socktools.h src/support/socktools.h NOCLASSES src/support/forkedcontr.h src/support/ForkedcallsController.h ForkedcallsController src/support/os.h src/support/os.h NOCLASSES src/support/FileMonitor.h src/support/FileMonitor.h FileMonitor src/support/copied_ptr.h src/support/copied_ptr.h copied_ptr src/support/translator.h src/support/Translator.h Translator src/support/filetools.C src/support/filetools.cpp NOCLASSES src/support/unlink.C src/support/unlink.cpp NOCLASSES src/support/os_win32.C src/support/os_win32.cpp GetFolderPath src/support/lstrings.C src/support/lstrings.cpp NOCLASSES src/support/qstring_helpers.C src/support/qstring_helpers.cpp NOCLASSES src/support/getcwd.C src/support/getcwd.cpp NOCLASSES src/support/systemcall.C src/support/Systemcall.cpp Systemcall src/support/lyxalgo.h src/support/lyxalgo.h NOCLASSES src/support/filefilterlist.h src/support/FileFilterList.h ['FileFilterList', 'Filter'] src/support/unicode.C src/support/unicode.cpp IconvProcessor src/support/userinfo.C src/support/userinfo.cpp NOCLASSES src/support/lyxtime.C src/support/lyxtime.cpp NOCLASSES src/support/kill.C src/support/kill.cpp NOCLASSES src/support/docstring.C src/support/docstring.cpp to_local8bit_failure src/support/os_cygwin.C src/support/os_cygwin.cpp NOCLASSES src/support/lyxsum.C src/support/lyxsum.cpp NOCLASSES src/support/environment.C src/support/environment.cpp NOCLASSES src/support/filetools.h src/support/filetools.h NOCLASSES src/support/textutils.C src/support/textutils.cpp NOCLASSES src/support/mkdir.C src/support/mkdir.cpp NOCLASSES src/support/forkedcall.C src/support/Forkedcall.cpp ['ForkedProcess', 'Forkedcall'] src/support/tempname.C src/support/tempname.cpp NOCLASSES src/support/os_win32.h src/support/os_win32.h GetFolderPath src/support/types.h src/support/types.h NOCLASSES src/support/lstrings.h src/support/lstrings.h NOCLASSES src/support/forkedcallqueue.C src/support/ForkedCallQueue.cpp ForkedCallQueue src/support/qstring_helpers.h src/support/qstring_helpers.h NOCLASSES src/support/convert.C src/support/convert.cpp NOCLASSES src/support/filename.C src/support/FileName.cpp ['FileName', 'DocFileName'] src/support/tests/convert.C src/support/tests/convert.cpp NOCLASSES src/support/tests/filetools.C src/support/tests/filetools.cpp NOCLASSES src/support/tests/lstrings.C src/support/tests/lstrings.cpp NOCLASSES src/support/tests/boost.C src/support/tests/boost.cpp NOCLASSES src/support/docstream.C src/support/docstream.cpp ['iconv_codecvt_facet_exception', 'idocfstream', 'odocfstream'] src/support/std_istream.h src/support/std_istream.h NOCLASSES src/support/systemcall.h src/support/Systemcall.h Systemcall src/support/chdir.C src/support/chdir.cpp NOCLASSES src/support/std_ostream.h src/support/std_ostream.h NOCLASSES src/support/unicode.h src/support/unicode.h IconvProcessor src/support/path.C src/support/Path.cpp Path src/support/fs_extras.C src/support/fs_extras.cpp NOCLASSES src/support/userinfo.h src/support/userinfo.h NOCLASSES src/support/lyxtime.h src/support/lyxtime.h NOCLASSES src/support/docstring.h src/support/docstring.h to_local8bit_failure src/support/debugstream.h src/support/debugstream.h basic_debugstream src/support/environment.h src/support/environment.h NOCLASSES src/support/textutils.h src/support/textutils.h NOCLASSES src/support/forkedcall.h src/support/Forkedcall.h ['ForkedProcess', 'Forkedcall'] src/support/socktools.C src/support/socktools.cpp NOCLASSES src/support/forkedcallqueue.h src/support/ForkedCallQueue.h ForkedCallQueue src/support/forkedcontr.C src/support/ForkedcallsController.cpp ForkedcallsController src/support/os.C src/support/os.cpp NOCLASSES src/support/convert.h src/support/convert.h NOCLASSES src/support/filename.h src/support/FileName.h ['FileName', 'DocFileName'] src/support/docstream.h src/support/docstream.h ['iconv_codecvt_facet_exception', 'idocfstream', 'odocfstream'] src/support/FileMonitor.C src/support/FileMonitor.cpp FileMonitor git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@18024 a592a061-630c-0410-9148-cb99ea01b6c8
2007-04-26 05:12:52 +00:00
#include "support/FileName.h"
#include "support/FileNameList.h"
#include "support/convert.h"
#include "support/debug.h"
#include "support/filetools.h"
#include "support/lstrings.h"
#include "support/qstring_helpers.h"
#include "support/os.h"
#include "support/Package.h"
Make libQtCore a support library like boost and implement encoding conversion from/to the local 8bit encoding with it. Only the autotools build system is updated, scons and cmake users need to add qt4 cpp flags when compiling libsupport, and link libsupport against libQtCore. * src/frontends/qt4/qt_helpers.[Ch] (toqstr, qchar_to_ucs4, ucs4_to_qchar, ucs4_to_qstring, qstring_to_ucs4, fromqstr): Move these qstring conversion functions from here ... * src/support/qstring_helpers.[Ch] ... to these new files * src/support/docstring.[Ch] (from_local8bit): new conversion function from local 8bit encoding to ucs4 (to_local8bit): new conversion function from ucs4 to local 8bit encoding to ucs4 (to_local8bit_failure): exception that is thrown by to_local8bit if the argument cannot be converted to the local encoding * src/support/filename.C (FileName::toFilesystemEncoding): implement with the help of QFile * src/support/Makefile.am: Add new files, qt4 cpp flags and link against libQtCore * src/client/client.C: Convert commandline input from local encoding to ucs4. Convert stuff that is sent to to the server to utf8, because LyX interprets it as utf8 on the other end of the pipe. * src/lyx_main.C (LyX::exec): convert commandline input from local encoding to utf8 (LyX::init): ditto (LyX::easyParse): ditto * development/scons/scons_manifest.py: Add new files * config/qt4.m4: Define new variables QT4_CORE_INCLUDES, QT4_CORE_LDFLAGS and QT4_CORE_LIB git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16257 a592a061-630c-0410-9148-cb99ea01b6c8
2006-12-12 20:19:46 +00:00
#include "support/qstring_helpers.h"
#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QList>
#include <QTemporaryFile>
#include <QTime>
#include "support/lassert.h"
#include <boost/scoped_array.hpp>
#include <map>
#include <sstream>
#include <fstream>
#include <algorithm>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_DIRECT_H
# include <direct.h>
#endif
#ifdef _WIN32
# include <windows.h>
#endif
#include <cerrno>
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#if defined(HAVE_MKSTEMP) && ! defined(HAVE_DECL_MKSTEMP)
extern "C" int mkstemp(char *);
#endif
#if !defined(HAVE_MKSTEMP) && defined(HAVE_MKTEMP)
# ifdef HAVE_IO_H
# include <io.h>
# endif
# ifdef HAVE_PROCESS_H
# include <process.h>
# endif
#endif
using namespace std;
namespace lyx {
namespace support {
/////////////////////////////////////////////////////////////////////
//
// FileName::Private
//
/////////////////////////////////////////////////////////////////////
struct FileName::Private
{
Private() {}
Private(string const & abs_filename) : fi(toqstr(abs_filename))
{
fi.setCaching(fi.exists() ? true : false);
}
///
inline void refresh()
{
// There seems to be a bug in Qt >= 4.2.0, at least, that causes problems with
// QFileInfo::refresh() on *nix. So we recreate the object in that case.
// FIXME: When Trolltech fixes the bug, we will have to replace 0x999999 below
// with the actual working minimum version.
#if defined(_WIN32) || (QT_VERSION >= 0x999999)
fi.refresh();
#else
fi = QFileInfo(fi.absoluteFilePath());
#endif
}
///
QFileInfo fi;
};
/////////////////////////////////////////////////////////////////////
//
// FileName
//
/////////////////////////////////////////////////////////////////////
FileName::FileName() : d(new Private)
{
}
FileName::FileName(string const & abs_filename)
: d(abs_filename.empty() ? new Private : new Private(abs_filename))
{
}
FileName::~FileName()
{
delete d;
}
FileName::FileName(FileName const & rhs) : d(new Private)
{
d->fi = rhs.d->fi;
}
FileName::FileName(FileName const & rhs, string const & suffix) : d(new Private)
{
set(rhs, suffix);
}
FileName & FileName::operator=(FileName const & rhs)
{
d->fi = rhs.d->fi;
return *this;
}
bool FileName::empty() const
{
return d->fi.absoluteFilePath().isEmpty();
}
bool FileName::isAbsolute() const
{
return d->fi.isAbsolute();
}
string FileName::absFilename() const
{
return fromqstr(d->fi.absoluteFilePath());
}
void FileName::set(string const & name)
{
d->fi.setFile(toqstr(name));
}
void FileName::set(FileName const & rhs, string const & suffix)
{
if (!rhs.d->fi.isDir())
d->fi.setFile(rhs.d->fi.filePath() + toqstr(suffix));
else
d->fi.setFile(QDir(rhs.d->fi.absoluteFilePath()), toqstr(suffix));
}
void FileName::erase()
{
d->fi = QFileInfo();
}
bool FileName::copyTo(FileName const & name) const
{
LYXERR(Debug::FILES, "Copying " << name);
QFile::remove(name.d->fi.absoluteFilePath());
bool success = QFile::copy(d->fi.absoluteFilePath(), name.d->fi.absoluteFilePath());
if (!success)
LYXERR0("FileName::copyTo(): Could not copy file "
<< *this << " to " << name);
return success;
}
bool FileName::renameTo(FileName const & name) const
{
bool success = QFile::rename(d->fi.absoluteFilePath(), name.d->fi.absoluteFilePath());
if (!success)
LYXERR0("Could not rename file " << *this << " to " << name);
return success;
}
bool FileName::moveTo(FileName const & name) const
{
QFile::remove(name.d->fi.absoluteFilePath());
bool success = QFile::rename(d->fi.absoluteFilePath(),
name.d->fi.absoluteFilePath());
if (!success)
LYXERR0("Could not move file " << *this << " to " << name);
return success;
}
bool FileName::changePermission(unsigned long int mode) const
{
#if defined (HAVE_CHMOD) && defined (HAVE_MODE_T)
if (::chmod(toFilesystemEncoding().c_str(), mode_t(mode)) != 0) {
LYXERR0("File " << *this << ": cannot change permission to "
<< mode << ".");
return false;
}
#endif
return true;
}
string FileName::toFilesystemEncoding() const
{
QByteArray const encoded = QFile::encodeName(d->fi.absoluteFilePath());
Make libQtCore a support library like boost and implement encoding conversion from/to the local 8bit encoding with it. Only the autotools build system is updated, scons and cmake users need to add qt4 cpp flags when compiling libsupport, and link libsupport against libQtCore. * src/frontends/qt4/qt_helpers.[Ch] (toqstr, qchar_to_ucs4, ucs4_to_qchar, ucs4_to_qstring, qstring_to_ucs4, fromqstr): Move these qstring conversion functions from here ... * src/support/qstring_helpers.[Ch] ... to these new files * src/support/docstring.[Ch] (from_local8bit): new conversion function from local 8bit encoding to ucs4 (to_local8bit): new conversion function from ucs4 to local 8bit encoding to ucs4 (to_local8bit_failure): exception that is thrown by to_local8bit if the argument cannot be converted to the local encoding * src/support/filename.C (FileName::toFilesystemEncoding): implement with the help of QFile * src/support/Makefile.am: Add new files, qt4 cpp flags and link against libQtCore * src/client/client.C: Convert commandline input from local encoding to ucs4. Convert stuff that is sent to to the server to utf8, because LyX interprets it as utf8 on the other end of the pipe. * src/lyx_main.C (LyX::exec): convert commandline input from local encoding to utf8 (LyX::init): ditto (LyX::easyParse): ditto * development/scons/scons_manifest.py: Add new files * config/qt4.m4: Define new variables QT4_CORE_INCLUDES, QT4_CORE_LDFLAGS and QT4_CORE_LIB git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16257 a592a061-630c-0410-9148-cb99ea01b6c8
2006-12-12 20:19:46 +00:00
return string(encoded.begin(), encoded.end());
}
FileName FileName::fromFilesystemEncoding(string const & name)
{
QByteArray const encoded(name.c_str(), name.length());
return FileName(fromqstr(QFile::decodeName(encoded)));
}
bool FileName::exists() const
{
return d->fi.exists();
}
bool FileName::isSymLink() const
{
return d->fi.isSymLink();
}
bool FileName::isFileEmpty() const
{
return d->fi.size() == 0;
}
bool FileName::isDirectory() const
{
return d->fi.isDir();
}
bool FileName::isReadOnly() const
{
return d->fi.isReadable() && !d->fi.isWritable();
}
bool FileName::isReadableDirectory() const
{
return d->fi.isDir() && d->fi.isReadable();
}
string FileName::onlyFileName() const
{
return fromqstr(d->fi.fileName());
}
string FileName::onlyFileNameWithoutExt() const
{
return fromqstr(d->fi.baseName());
}
FileName FileName::onlyPath() const
{
FileName path;
path.d->fi.setFile(d->fi.path());
return path;
}
bool FileName::isReadableFile() const
{
return d->fi.isFile() && d->fi.isReadable();
}
bool FileName::isWritable() const
{
return d->fi.isWritable();
}
bool FileName::isDirWritable() const
{
LASSERT(d->fi.isDir(), return false);
QFileInfo tmp(d->fi.absoluteDir(), "lyxwritetest");
QTemporaryFile qt_tmp(tmp.absoluteFilePath());
if (qt_tmp.open()) {
LYXERR(Debug::FILES, "Directory " << *this << " is writable");
return true;
}
LYXERR(Debug::FILES, "Directory " << *this << " is not writable");
return false;
}
FileNameList FileName::dirList(string const & ext) const
{
FileNameList dirlist;
if (!isDirectory()) {
LYXERR0("Directory '" << *this << "' does not exist!");
return dirlist;
}
QDir dir = d->fi.absoluteDir();
if (!ext.empty()) {
QString filter;
switch (ext[0]) {
case '.': filter = "*" + toqstr(ext); break;
case '*': filter = toqstr(ext); break;
default: filter = "*." + toqstr(ext);
}
dir.setNameFilters(QStringList(filter));
LYXERR(Debug::FILES, "filtering on extension "
<< fromqstr(filter) << " is requested.");
}
QFileInfoList list = dir.entryInfoList();
for (int i = 0; i != list.size(); ++i) {
FileName fi(fromqstr(list.at(i).absoluteFilePath()));
dirlist.push_back(fi);
LYXERR(Debug::FILES, "found file " << fi);
}
return dirlist;
}
static string createTempFile(QString const & mask)
{
QTemporaryFile qt_tmp(mask);
if (qt_tmp.open()) {
string const temp_file = fromqstr(qt_tmp.fileName());
LYXERR(Debug::FILES, "Temporary file `" << temp_file << "' created.");
return temp_file;
}
LYXERR(Debug::FILES, "Unable to create temporary file with following template: "
<< qt_tmp.fileTemplate());
return string();
}
FileName FileName::tempName(FileName const & temp_dir, string const & mask)
{
QFileInfo tmp_fi(QDir(temp_dir.d->fi.absoluteFilePath()), toqstr(mask));
LYXERR(Debug::FILES, "Temporary file in " << tmp_fi.absoluteFilePath());
return FileName(createTempFile(tmp_fi.absoluteFilePath()));
}
FileName FileName::tempName(string const & mask)
{
return tempName(package().temp_dir(), mask);
}
FileName FileName::getcwd()
{
return FileName(".");
}
FileName FileName::tempPath()
{
return FileName(fromqstr(QDir::tempPath()));
}
time_t FileName::lastModified() const
{
// QFileInfo caches information about the file. So, in case this file has
// been touched between the object creation and now, we refresh the file
// information.
d->refresh();
return d->fi.lastModified().toTime_t();
}
bool FileName::chdir() const
{
return QDir::setCurrent(d->fi.absoluteFilePath());
}
extern unsigned long sum(char const * file);
unsigned long FileName::checksum() const
{
if (!exists()) {
//LYXERR0("File \"" << absFilename() << "\" does not exist!");
return 0;
}
// a directory may be passed here so we need to test it. (bug 3622)
if (isDirectory()) {
LYXERR0('"' << absFilename() << "\" is a directory!");
return 0;
}
if (!lyxerr.debugging(Debug::FILES))
return sum(absFilename().c_str());
QTime t;
t.start();
unsigned long r = sum(absFilename().c_str());
lyxerr << "Checksumming \"" << absFilename() << "\" lasted "
<< t.elapsed() << " ms." << endl;
return r;
}
bool FileName::removeFile() const
{
bool const success = QFile::remove(d->fi.absoluteFilePath());
if (!success && exists())
LYXERR0("Could not delete file " << *this);
return success;
}
static bool rmdir(QFileInfo const & fi)
{
QDir dir(fi.absoluteFilePath());
QFileInfoList list = dir.entryInfoList();
bool success = true;
for (int i = 0; i != list.size(); ++i) {
if (list.at(i).fileName() == ".")
continue;
if (list.at(i).fileName() == "..")
continue;
bool removed;
if (list.at(i).isDir()) {
LYXERR(Debug::FILES, "Removing dir "
<< fromqstr(list.at(i).absoluteFilePath()));
removed = rmdir(list.at(i));
}
else {
LYXERR(Debug::FILES, "Removing file "
<< fromqstr(list.at(i).absoluteFilePath()));
removed = dir.remove(list.at(i).fileName());
}
if (!removed) {
success = false;
LYXERR0("Could not delete "
<< fromqstr(list.at(i).absoluteFilePath()));
}
}
QDir parent = fi.absolutePath();
success &= parent.rmdir(fi.fileName());
return success;
}
bool FileName::destroyDirectory() const
{
bool const success = rmdir(d->fi);
if (!success)
LYXERR0("Could not delete " << *this);
return success;
}
static int mymkdir(char const * pathname, unsigned long int mode)
{
// FIXME: why don't we have mode_t in lyx::mkdir prototype ??
#if HAVE_MKDIR
# if MKDIR_TAKES_ONE_ARG
// MinGW32
return ::mkdir(pathname);
// FIXME: "Permissions of created directories are ignored on this system."
# else
// POSIX
return ::mkdir(pathname, mode_t(mode));
# endif
#elif defined(_WIN32)
// plain Windows 32
return CreateDirectory(pathname, 0) != 0 ? 0 : -1;
// FIXME: "Permissions of created directories are ignored on this system."
#elif HAVE__MKDIR
return ::_mkdir(pathname);
// FIXME: "Permissions of created directories are ignored on this system."
#else
# error "Don't know how to create a directory on this system."
#endif
}
bool FileName::createDirectory(int permission) const
{
LASSERT(!empty(), /**/);
return mymkdir(toFilesystemEncoding().c_str(), permission) == 0;
}
bool FileName::createPath() const
{
LASSERT(!empty(), /**/);
if (isDirectory())
return true;
QDir dir;
bool success = dir.mkpath(d->fi.absoluteFilePath());
if (!success)
LYXERR0("Cannot create path '" << *this << "'!");
return success;
}
docstring const FileName::absoluteFilePath() const
{
return qstring_to_ucs4(d->fi.absoluteFilePath());
}
docstring FileName::displayName(int threshold) const
{
return makeDisplayPath(absFilename(), threshold);
}
docstring FileName::fileContents(string const & encoding) const
{
if (!isReadableFile()) {
LYXERR0("File '" << *this << "' is not redable!");
return docstring();
}
QFile file(d->fi.absoluteFilePath());
if (!file.open(QIODevice::ReadOnly)) {
LYXERR0("File '" << *this
<< "' could not be opened in read only mode!");
return docstring();
}
QByteArray contents = file.readAll();
file.close();
if (contents.isEmpty()) {
LYXERR(Debug::FILES, "File '" << *this
<< "' is either empty or some error happened while reading it.");
return docstring();
}
QString s;
if (encoding.empty() || encoding == "UTF-8")
s = QString::fromUtf8(contents.data());
else if (encoding == "ascii")
s = QString::fromAscii(contents.data());
else if (encoding == "local8bit")
s = QString::fromLocal8Bit(contents.data());
else if (encoding == "latin1")
s = QString::fromLatin1(contents.data());
return qstring_to_ucs4(s);
}
void FileName::changeExtension(string const & extension)
{
// FIXME: use Qt native methods...
string const oldname = absFilename();
string::size_type const last_slash = oldname.rfind('/');
string::size_type last_dot = oldname.rfind('.');
if (last_dot < last_slash && last_slash != string::npos)
last_dot = string::npos;
string ext;
// Make sure the extension starts with a dot
if (!extension.empty() && extension[0] != '.')
ext= '.' + extension;
else
ext = extension;
set(oldname.substr(0, last_dot) + ext);
}
string FileName::guessFormatFromContents() const
{
// the different filetypes and what they contain in one of the first lines
// (dots are any characters). (Herbert 20020131)
// AGR Grace...
// BMP BM...
// EPS %!PS-Adobe-3.0 EPSF...
// FIG #FIG...
// FITS ...BITPIX...
// GIF GIF...
// JPG JFIF
// PDF %PDF-...
// PNG .PNG...
// PBM P1... or P4 (B/W)
// PGM P2... or P5 (Grayscale)
// PPM P3... or P6 (color)
// PS %!PS-Adobe-2.0 or 1.0, no "EPSF"!
// SGI \001\332... (decimal 474)
// TGIF %TGIF...
// TIFF II... or MM...
// XBM ..._bits[]...
// XPM /* XPM */ sometimes missing (f.ex. tgif-export)
// ...static char *...
// XWD \000\000\000\151 (0x00006900) decimal 105
//
// GZIP \037\213 http://www.ietf.org/rfc/rfc1952.txt
// ZIP PK... http://www.halyava.ru/document/ind_arch.htm
// Z \037\235 UNIX compress
// paranoia check
if (empty() || !isReadableFile())
return string();
ifstream ifs(toFilesystemEncoding().c_str());
if (!ifs)
// Couldn't open file...
return string();
// gnuzip
static string const gzipStamp = "\037\213";
// PKZIP
static string const zipStamp = "PK";
// compress
static string const compressStamp = "\037\235";
// Maximum strings to read
int const max_count = 50;
int count = 0;
string str;
string format;
bool firstLine = true;
while ((count++ < max_count) && format.empty()) {
if (ifs.eof()) {
LYXERR(Debug::GRAPHICS, "filetools(getFormatFromContents)\n"
<< "\tFile type not recognised before EOF!");
break;
}
getline(ifs, str);
string const stamp = str.substr(0, 2);
if (firstLine && str.size() >= 2) {
// at first we check for a zipped file, because this
// information is saved in the first bytes of the file!
// also some graphic formats which save the information
// in the first line, too.
if (prefixIs(str, gzipStamp)) {
format = "gzip";
} else if (stamp == zipStamp) {
format = "zip";
} else if (stamp == compressStamp) {
format = "compress";
// the graphics part
} else if (stamp == "BM") {
format = "bmp";
} else if (stamp == "\001\332") {
format = "sgi";
// PBM family
// Don't need to use str.at(0), str.at(1) because
// we already know that str.size() >= 2
} else if (str[0] == 'P') {
switch (str[1]) {
case '1':
case '4':
format = "pbm";
break;
case '2':
case '5':
format = "pgm";
break;
case '3':
case '6':
format = "ppm";
}
break;
} else if ((stamp == "II") || (stamp == "MM")) {
format = "tiff";
} else if (prefixIs(str,"%TGIF")) {
format = "tgif";
} else if (prefixIs(str,"#FIG")) {
format = "fig";
} else if (prefixIs(str,"GIF")) {
format = "gif";
} else if (str.size() > 3) {
int const c = ((str[0] << 24) & (str[1] << 16) &
(str[2] << 8) & str[3]);
if (c == 105) {
format = "xwd";
}
}
firstLine = false;
}
if (!format.empty())
break;
else if (contains(str,"EPSF"))
// dummy, if we have wrong file description like
// %!PS-Adobe-2.0EPSF"
format = "eps";
else if (contains(str, "Grace"))
format = "agr";
else if (contains(str, "JFIF"))
format = "jpg";
else if (contains(str, "%PDF"))
format = "pdf";
else if (contains(str, "PNG"))
format = "png";
else if (contains(str, "%!PS-Adobe")) {
// eps or ps
ifs >> str;
if (contains(str,"EPSF"))
format = "eps";
else
format = "ps";
}
else if (contains(str, "_bits[]"))
format = "xbm";
else if (contains(str, "XPM") || contains(str, "static char *"))
format = "xpm";
else if (contains(str, "BITPIX"))
format = "fits";
}
if (!format.empty()) {
LYXERR(Debug::GRAPHICS, "Recognised Fileformat: " << format);
return format;
}
LYXERR(Debug::GRAPHICS, "filetools(getFormatFromContents)\n"
<< "\tCouldn't find a known format!");
return string();
}
bool FileName::isZippedFile() const
{
string const type = guessFormatFromContents();
return contains("gzip zip compress", type) && !type.empty();
}
docstring const FileName::relPath(string const & path) const
{
// FIXME UNICODE
return makeRelPath(absoluteFilePath(), from_utf8(path));
}
bool operator==(FileName const & lhs, FileName const & rhs)
{
// FIXME: We need to solve this warning from Qt documentation:
// * Long and short file names that refer to the same file on Windows are
// treated as if they referred to different files.
// This is supposed to be fixed for Qt5.
if (lhs.empty())
// QFileInfo::operator==() returns false if the two QFileInfo are empty.
return rhs.empty();
if (rhs.empty())
// Avoid unnecessary checks below.
return false;
lhs.d->refresh();
rhs.d->refresh();
if (!lhs.d->fi.isSymLink() && !rhs.d->fi.isSymLink())
return lhs.d->fi == rhs.d->fi;
// FIXME: When/if QFileInfo support symlink comparison, remove this code.
QFileInfo fi1(lhs.d->fi);
if (fi1.isSymLink())
fi1 = QFileInfo(fi1.symLinkTarget());
QFileInfo fi2(rhs.d->fi);
if (fi2.isSymLink())
fi2 = QFileInfo(fi2.symLinkTarget());
return fi1 == fi2;
}
bool operator!=(FileName const & lhs, FileName const & rhs)
{
return !(operator==(lhs, rhs));
}
bool operator<(FileName const & lhs, FileName const & rhs)
{
return lhs.absFilename() < rhs.absFilename();
}
bool operator>(FileName const & lhs, FileName const & rhs)
{
return lhs.absFilename() > rhs.absFilename();
}
ostream & operator<<(ostream & os, FileName const & filename)
{
return os << filename.absFilename();
}
/////////////////////////////////////////////////////////////////////
//
// DocFileName
//
/////////////////////////////////////////////////////////////////////
DocFileName::DocFileName()
: save_abs_path_(true)
{}
DocFileName::DocFileName(string const & abs_filename, bool save_abs)
: FileName(abs_filename), save_abs_path_(save_abs), zipped_valid_(false)
{}
DocFileName::DocFileName(FileName const & abs_filename, bool save_abs)
: FileName(abs_filename), save_abs_path_(save_abs), zipped_valid_(false)
{}
void DocFileName::set(string const & name, string const & buffer_path)
{
FileName::set(name);
bool const nameIsAbsolute = isAbsolute();
save_abs_path_ = nameIsAbsolute;
if (!nameIsAbsolute)
FileName::set(makeAbsPath(name, buffer_path).absFilename());
zipped_valid_ = false;
}
void DocFileName::erase()
{
FileName::erase();
zipped_valid_ = false;
}
string DocFileName::relFilename(string const & path) const
{
// FIXME UNICODE
return to_utf8(relPath(path));
}
string DocFileName::outputFilename(string const & path) const
{
return save_abs_path_ ? absFilename() : relFilename(path);
}
string DocFileName::mangledFilename(string const & dir) const
{
// We need to make sure that every DocFileName instance for a given
// filename returns the same mangled name.
typedef map<string, string> MangledMap;
static MangledMap mangledNames;
MangledMap::const_iterator const it = mangledNames.find(absFilename());
if (it != mangledNames.end())
return (*it).second;
string const name = absFilename();
// Now the real work
string mname = os::internal_path(name);
// Remove the extension.
mname = support::changeExtension(name, string());
// The mangled name must be a valid LaTeX name.
// The list of characters to keep is probably over-restrictive,
// but it is not really a problem.
// Apart from non-ASCII characters, at least the following characters
// are forbidden: '/', '.', ' ', and ':'.
// On windows it is not possible to create files with '<', '>' or '?'
// in the name.
static string const keep = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"+,-0123456789;=";
string::size_type pos = 0;
while ((pos = mname.find_first_not_of(keep, pos)) != string::npos)
mname[pos++] = '_';
// Add the extension back on
mname = support::changeExtension(mname, getExtension(name));
// Prepend a counter to the filename. This is necessary to make
// the mangled name unique.
static int counter = 0;
ostringstream s;
s << counter++ << mname;
mname = s.str();
// MiKTeX's YAP (version 2.4.1803) crashes if the file name
// is longer than about 160 characters. MiKTeX's pdflatex
// is even pickier. A maximum length of 100 has been proven to work.
// If dir.size() > max length, all bets are off for YAP. We truncate
// the filename nevertheless, keeping a minimum of 10 chars.
string::size_type max_length = max(100 - ((int)dir.size() + 1), 10);
// If the mangled file name is too long, hack it to fit.
// We know we're guaranteed to have a unique file name because
// of the counter.
if (mname.size() > max_length) {
int const half = (int(max_length) / 2) - 2;
if (half > 0) {
mname = mname.substr(0, half) + "___" +
mname.substr(mname.size() - half);
}
}
mangledNames[absFilename()] = mname;
return mname;
}
bool DocFileName::isZipped() const
{
if (!zipped_valid_) {
zipped_ = isZippedFile();
zipped_valid_ = true;
}
return zipped_;
}
string DocFileName::unzippedFilename() const
{
return unzippedFileName(absFilename());
}
bool operator==(DocFileName const & lhs, DocFileName const & rhs)
{
return static_cast<FileName const &>(lhs)
== static_cast<FileName const &>(rhs)
&& lhs.saveAbsPath() == rhs.saveAbsPath();
}
bool operator!=(DocFileName const & lhs, DocFileName const & rhs)
{
return !(lhs == rhs);
}
} // namespace support
} // namespace lyx