Encapsulate libmagic support in a class

This makes the code much easier to read and, additionally, allows to
parse the magic file with magic_load() only once per session.

As a result, getFormatFromFile is slightly faster.
This commit is contained in:
Jean-Marc Lasgouttes 2018-07-03 11:36:12 +02:00
parent 1a96b0d184
commit 4c6a341ab5
3 changed files with 107 additions and 47 deletions

View File

@ -19,11 +19,12 @@
#include "frontends/alert.h" //to be removed?
#include "support/debug.h"
#include "support/docstream.h"
#include "support/filetools.h"
#include "support/gettext.h"
#include "support/lstrings.h"
#include "support/Magic.h"
#include "support/mutex.h"
#include "support/docstream.h"
#include "support/os.h"
#include "support/PathChanger.h"
#include "support/Systemcall.h"
@ -39,10 +40,6 @@
#include "support/linkback/LinkBackProxy.h"
#endif
#ifdef HAVE_MAGIC_H
#include <magic.h>
#endif
using namespace std;
using namespace lyx::support;
@ -407,52 +404,37 @@ string Formats::getFormatFromFile(FileName const & filename) const
string psformat;
string format;
#ifdef HAVE_MAGIC_H
if (filename.exists()) {
magic_t magic_cookie = magic_open(MAGIC_MIME);
if (magic_cookie) {
if (magic_load(magic_cookie, NULL) != 0) {
LYXERR(Debug::GRAPHICS, "Formats::getFormatFromFile\n"
<< "\tCouldn't load magic database - "
<< magic_error(magic_cookie));
} else {
char const * result = magic_file(magic_cookie,
filename.toFilesystemEncoding().c_str());
string mime;
if (result)
mime = token(result, ';', 0);
else {
LYXERR(Debug::GRAPHICS, "Formats::getFormatFromFile\n"
<< "\tCouldn't query magic database - "
<< magic_error(magic_cookie));
}
// our own detection is better for binary files (can be anything)
// and different plain text formats
if (!mime.empty() && mime != "application/octet-stream" &&
mime != "text/plain") {
Formats::const_iterator cit =
find_if(formatlist_.begin(), formatlist_.end(),
FormatMimeEqual(mime));
if (cit != formatlist_.end()) {
LYXERR(Debug::GRAPHICS, "\tgot format from MIME type: "
<< mime << " -> " << cit->name());
// See special eps/ps handling below
if (mime == "application/postscript")
psformat = cit->name();
else
format = cit->name();
}
}
// one instance of Magic that will be reused for next calls
// This avoids to read the magic file everytime
// If libmagic is not available, Magic::file returns an empty string.
static Magic magic;
string const result = magic.file(filename.toFilesystemEncoding());
string const mime = token(result, ';', 0);
// our own detection is better for binary files (can be anything)
// and different plain text formats
if (!mime.empty() && mime != "application/octet-stream" &&
mime != "text/plain") {
Formats::const_iterator cit =
find_if(formatlist_.begin(), formatlist_.end(),
FormatMimeEqual(mime));
if (cit != formatlist_.end()) {
LYXERR(Debug::GRAPHICS, "\tgot format from MIME type: "
<< mime << " -> " << cit->name());
// See special eps/ps handling below
if (mime == "application/postscript")
psformat = cit->name();
else
format = cit->name();
}
magic_close(magic_cookie);
// libmagic recognizes as latex also some formats of ours
// such as pstex and pdftex. Therefore we have to perform
// additional checks in this case (bug 9244).
if (!format.empty() && format != "latex")
return format;
}
// libmagic recognizes as latex also some formats of ours
// such as pstex and pdftex. Therefore we have to perform
// additional checks in this case (bug 9244).
if (!format.empty() && format != "latex")
return format;
}
#endif
string const ext = getExtension(filename.absFileName());
if (format.empty()) {

77
src/support/Magic.h Normal file
View File

@ -0,0 +1,77 @@
// -*- C++ -*-
/**
* \file Magic.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Jean-Marc Lasgouttes
*
* Full author contact details are available in file CREDITS.
*/
#ifndef LYX_MAGIC_H
#define LYX_MAGIC_H
namespace lyx {
#ifdef HAVE_MAGIC_H
#include "support/debug.h"
#include <magic.h>
class Magic {
public:
Magic() : ok_(false) {
cookie_ = magic_open(MAGIC_MIME);
if (cookie_) {
if (magic_load(cookie_, NULL) != 0)
LYXERR(Debug::GRAPHICS, "Magic: couldn't load magic database - "
<< magic_error(cookie_));
else
ok_ = true;
}
}
~Magic() {
if(cookie_)
magic_close(cookie_);
}
// returns a string of the form "mime-type;encoding", or an empty string on error.
std::string file(std::string const & name) const {
if (!ok_)
return std::string();
char const * result = magic_file(cookie_, name.c_str());
if (result)
return result;
else
LYXERR(Debug::GRAPHICS, "Magic: couldn't query magic database - "
<< magic_error(cookie_));
return std::string();
}
private:
magic_t cookie_;
bool ok_;
};
#else // !HAVE_MAGIC_T
// A dummy Magic class that always returns an empty result
class Magic {
public:
Magic() {
LYXERR(Debug::GRAPHICS, "Magic: libmagic support not configured");
}
std::string file(std::string const & name) const { return empty_string; }
};
#endif // HAVE_MAGIC_T
}
#endif // LYX_MAGIC_H

View File

@ -76,6 +76,7 @@ liblyxsupport_a_SOURCES = \
lyxlib.h \
lyxtime.cpp \
lyxtime.h \
Magic.h \
mutex.h \
mutex.cpp \
Messages.cpp \