]> git.lyx.org Git - lyx.git/blobdiff - src/support/filetools.cpp
Make GraphicsConverter threadsafe
[lyx.git] / src / support / filetools.cpp
index fd04c6a98414e701920683503048745ad97aed20..d167d6a94cb1a52ddd7b5401c6a2c17a513ee3f8 100644 (file)
 #include "support/qstring_helpers.h"
 
 #include <QDir>
+#include <QTemporaryFile>
 
 #include "support/lassert.h"
 #include "support/regex.h"
 
 #include <fcntl.h>
+#ifdef HAVE_MAGIC_H
+#include <magic.h>
+#endif
 
 #include <cerrno>
 #include <cstdlib>
@@ -90,6 +94,60 @@ bool isValidDVIFileName(string const & filename)
 }
 
 
+bool isBinaryFile(FileName const & filename)
+{
+       bool isbinary = false;
+       if (filename.empty() || !filename.exists())
+               return isbinary;
+
+#ifdef HAVE_MAGIC_H
+       magic_t magic_cookie = magic_open(MAGIC_MIME_ENCODING);
+       if (magic_cookie) {
+               bool detected = true;
+               if (magic_load(magic_cookie, NULL) != 0) {
+                       LYXERR(Debug::FILES, "isBinaryFile: "
+                               "Could not load magic database - "
+                               << magic_error(magic_cookie));
+                       detected = false;
+               } else {
+                       char const *charset = magic_file(magic_cookie,
+                                       filename.toFilesystemEncoding().c_str());
+                       isbinary = contains(charset, "binary");
+               }
+               magic_close(magic_cookie);
+               if (detected)
+                       return isbinary;
+       }
+#endif
+       // Try by looking for binary chars at the beginning of the file.
+       // Note that this is formally not correct, since count_bin_chars
+       // expects utf8, and the passed string can be anything: plain text
+       // in any encoding, or really binary data. In practice it works,
+       // since QString::fromUtf8() drops invalid utf8 sequences, and
+       // while the exact number may not be correct, we still get a high
+       // number for truly binary files.
+
+       ifstream ifs(filename.toFilesystemEncoding().c_str());
+       if (!ifs)
+               return isbinary;
+
+       // Maximum strings to read
+       int const max_count = 50;
+
+       // Maximum number of binary chars allowed
+       int const max_bin = 5;
+
+       int count = 0;
+       int binchars = 0;
+       string str;
+       while (count++ < max_count && !ifs.eof()) {
+               getline(ifs, str);
+               binchars += count_bin_chars(str);
+       }
+       return binchars > max_bin;
+}
+
+
 string const latex_path(string const & original_path,
                latex_path_extension extension,
                latex_path_dots dots)
@@ -337,11 +395,15 @@ FileName const imageLibFileSearch(string & dir, string const & name,
 }
 
 
-string const libScriptSearch(string const & command_in)
+string const commandPrep(string const & command_in)
 {
        static string const token_scriptpath = "$$s/";
+       string const python_call = "python -tt";
 
        string command = command_in;
+       if (prefixIs(command_in, python_call))
+               command = os::python() + command_in.substr(python_call.length());
+
        // Find the starting position of "$$s/"
        string::size_type const pos1 = command.find(token_scriptpath);
        if (pos1 == string::npos)
@@ -362,8 +424,7 @@ string const libScriptSearch(string const & command_in)
                command.erase(pos1, 4);
        } else {
                quote_style style = quote_shell;
-               string const python_call = "python -tt";
-               if (prefixIs(command, python_call) || prefixIs(command, os::python()))
+               if (prefixIs(command, os::python()))
                        style = quote_python;
 
                // Replace "$$s/foo/some_script" with "<path to>/some_script".
@@ -375,12 +436,35 @@ string const libScriptSearch(string const & command_in)
 }
 
 
+static string createTempFile(QString const & mask)
+{
+       // FIXME: This is not safe. QTemporaryFile creates a file in open(),
+       //        but the file is deleted when qt_tmp goes out of scope.
+       //        Therefore the next call to createTempFile() may create the
+       //        same file again. To make this safe the QTemporaryFile object
+       //        needs to be kept for the whole life time of the temp file name.
+       //        This could be achieved by creating a class TempDir (like
+       //        TempFile, but using a currentlky non-existing
+       //        QTemporaryDirectory object).
+       QTemporaryFile qt_tmp(mask + ".XXXXXXXXXXXX");
+       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();
+}
+
+
 static FileName createTmpDir(FileName const & tempdir, string const & mask)
 {
        LYXERR(Debug::FILES, "createTmpDir: tempdir=`" << tempdir << "'\n"
                << "createTmpDir:    mask=`" << mask << '\'');
 
-       FileName const tmpfl = FileName::tempName(tempdir, mask);
+       QFileInfo tmp_fi(QDir(toqstr(tempdir.absFileName())), toqstr(mask));
+       FileName const tmpfl(createTempFile(tmp_fi.absoluteFilePath()));
 
        if (tmpfl.empty() || !tmpfl.createDirectory(0700)) {
                LYXERR0("LyX could not create temporary directory in " << tempdir
@@ -837,7 +921,7 @@ bool readLink(FileName const & file, FileName & link)
        string const encoded = file.toFilesystemEncoding();
 #ifdef HAVE_DEF_PATH_MAX
        char linkbuffer[PATH_MAX + 1];
-       int const nRead = ::readlink(encoded.c_str(),
+       ssize_t const nRead = ::readlink(encoded.c_str(),
                                     linkbuffer, sizeof(linkbuffer) - 1);
        if (nRead <= 0)
                return false;
@@ -851,7 +935,7 @@ bool readLink(FileName const & file, FileName & link)
                if (nRead < 0) {
                        return false;
                }
-               if (nRead < buf.size() - 1) {
+               if (static_cast<size_t>(nRead) < buf.size() - 1) {
                        break;
                }
                buf.resize(buf.size() * 2);