kdecore: rework KMimeType

more accurate probing then before, notably by probing the file content
from the file slave (only the name was checked before because the
filepath was not a full path in some cases and the file could not be
open)

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2024-05-04 08:06:42 +03:00
parent ee4c56ad5e
commit 817b7a4aab
26 changed files with 175 additions and 510 deletions

View file

@ -122,6 +122,19 @@ static QString kFolderIconName(const KUrl &_url)
return icon;
}
KMimeType::KMimeType(const QString &fullpath, const QString &name)
: QSharedData(),
d_ptr(new KMimeTypePrivate(fullpath))
{
d_ptr->m_strName = name;
}
KMimeType::~KMimeType()
{
delete d_ptr;
}
KMimeType::Ptr KMimeType::defaultMimeTypePtr()
{
return KMimeTypeRepository::self()->defaultMimeTypePtr();
@ -163,17 +176,23 @@ bool KMimeType::isBufferBinaryData(const QByteArray &data)
return false;
}
static KMimeType::Ptr findFromMode(const QString &path,
mode_t mode,
bool is_local_file)
KMimeType::Ptr KMimeType::findByUrl(const KUrl &url, mode_t mode,
bool fast_mode, int* accuracy)
{
if (is_local_file && (mode == 0 || mode == (mode_t)-1)) {
KMimeTypeRepository::self()->checkEssentialMimeTypes();
const bool is_local = url.isLocalFile();
const QString localfile = url.toLocalFile();
if (is_local && mode <= 0) {
KDE_struct_stat buff;
if (KDE::stat(path, &buff) != -1) {
if (KDE::stat(localfile, &buff) != -1) {
mode = buff.st_mode;
}
}
if (accuracy) {
*accuracy = 100;
}
if (S_ISDIR(mode)) {
return KMimeType::mimeType(QLatin1String("inode/directory"));
} else if (S_ISCHR(mode)) {
@ -185,220 +204,86 @@ static KMimeType::Ptr findFromMode(const QString &path,
} else if (S_ISSOCK(mode)) {
return KMimeType::mimeType(QLatin1String("inode/socket"));
}
// remote executable file? stop here (otherwise findFromContent can do that better for local files)
if (!is_local_file && S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
return KMimeType::mimeType(QLatin1String("application/x-executable"));
}
return KMimeType::Ptr();
}
/*
As agreed on the XDG list (and unlike the current shared-mime spec):
Glob-matching should prefer derived mimetype over base mimetype, and longer matches
over shorter ones. However if two globs of the same length match the file, and the two
matches are not related in the inheritance tree, then we have a "glob conflict", which
will be resolved below.
If only one glob matches, use that
If no glob matches, sniff and use that
If several globs matches, and sniffing gives a result we do:
if sniffed prio >= 80, use sniffed type
for glob_match in glob_matches:
if glob_match is subclass or equal to sniffed_type, use glob_match
If several globs matches, and sniffing fails, or doesn't help:
fall back to the first glob match
This algorithm only sniffs when there is some uncertainty with the
extension matching (thus, it's usable for a file manager).
Note: in KDE we want the file views to sniff in a delayed manner.
So there's also a fast mode which is:
if no glob matches, or if more than one glob matches, use default mimetype and mark as "can be refined".
*/
KMimeType::Ptr KMimeType::findByUrlHelper(const KUrl &_url, mode_t mode,
bool is_local_file,
QIODevice *device,
int* accuracy)
{
KMimeTypeRepository::self()->checkEssentialMimeTypes();
const QString path = is_local_file ? _url.toLocalFile() : _url.path();
if (accuracy) {
*accuracy = 100;
}
// Look at mode first
KMimeType::Ptr mimeFromMode = findFromMode(path, mode, is_local_file);
if (mimeFromMode) {
return mimeFromMode;
}
if (device && !device->isOpen()) {
if (!device->open(QIODevice::ReadOnly)) {
device = nullptr;
}
}
QStringList mimeList;
// Try to find out by looking at the filename (if there's one)
const QString fileName(_url.fileName());
if (!fileName.isEmpty() && !path.endsWith(QLatin1Char('/'))) {
// and if we can trust it (e.g. don't trust *.pl over HTTP, could be anything)
if (is_local_file || KProtocolInfo::determineMimetypeFromExtension(_url.protocol())) {
mimeList = KMimeTypeRepository::self()->findFromFileName(fileName);
}
}
QStringList globMimeList = mimeList;
// Found one glob match exactly: OK, use that like the reference xdgmime
// implementation.
if (mimeList.count() == 1) {
if (accuracy) {
*accuracy = 50;
}
const QString selectedMime = mimeList.at(0);
KMimeType::Ptr mime = mimeType(selectedMime);
if (!mime) {
// #265188 - this can happen when an old globs file is lying around after
// the packages xml file was removed.
kWarning() << "Glob file refers to" << selectedMime << "but this mimetype does not exist!";
mimeList.clear();
} else {
return mime;
}
}
// Try the magic matches (if we can read the data)
if (device) {
int magicAccuracy;
KMimeType::Ptr mime = KMimeTypeRepository::self()->findFromContent(device, &magicAccuracy);
// mime can't be 0, except in case of install problems.
// However we get magicAccuracy==0 for octet-stream, i.e. no magic match found.
//kDebug(servicesDebugArea()) << "findFromContent said" << (mime?mime->name():QString()) << "with accuracy" << magicAccuracy;
if (mime && magicAccuracy > 0) {
// Disambiguate conflicting extensions (if magic found something and the magicrule was <80)
if (magicAccuracy < 80 && !mimeList.isEmpty()) {
// "for glob_match in glob_matches:"
// "if glob_match is subclass or equal to sniffed_type, use glob_match"
const QString sniffedMime = mime->name();
foreach(const QString &m, mimeList) {
KMimeType::Ptr mimeFromPattern = KMimeType::mimeType(m);
//kDebug(servicesDebugArea()) << "sniffedMime=" << sniffedMime << "mimeFromPattern=" << mimeFromPattern->name();
if (mimeFromPattern && mimeFromPattern->is(sniffedMime)) {
// We have magic + pattern pointing to this, so it's a pretty good match
if (accuracy) {
*accuracy = 100;
}
return mimeFromPattern;
}
}
}
if (accuracy) {
*accuracy = magicAccuracy;
}
return mime;
}
}
// Find a fallback from the protocol
if (accuracy) {
*accuracy = 10;
}
// ## this breaks with proxying; find a way to move proxying info to kdecore's kprotocolinfo?
// ## or hardcode the only case of proxying that we ever had? (ftp-over-http)
KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_url.protocol());
QString def;
if (prot) {
def = prot->defaultMimeType();
}
if (!def.isEmpty() && def != defaultMimeType()) {
// The protocol says it always returns a given mimetype (e.g. text/html for "man:")
KMimeType::Ptr mime = mimeType(def);
if (mime) {
return mime;
}
}
if (path.endsWith( QLatin1Char('/')) || path.isEmpty()) {
// We have no filename at all. Maybe the protocol has a setting for
// which mimetype this means (e.g. directory).
// For HTTP (def==defaultMimeType()) we don't assume anything,
// because of redirections (e.g. freshmeat downloads).
if (def.isEmpty()) {
// Assume inode/directory, if the protocol supports listing.
KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_url.protocol());
if (prot && prot->supportsListing()) {
KMimeType::Ptr mime = mimeType(QLatin1String("inode/directory"));
if (mime) { // only 0 if no mimetypes installed
return mime;
}
} else {
// == 'no idea', e.g. for "<proto>:,foo/"
return defaultMimeTypePtr();
}
}
}
if (globMimeList.count() > 0) {
// Glob with no magic (e.g. application/x-cd-image)
KMimeType::Ptr mime = mimeType(globMimeList.at(0));
if (mime) {
const QString fileName = url.fileName();
const QString protocol = url.protocol();
QStringList mimeList;
if (!fileName.isEmpty() && KProtocolInfo::determineMimetypeFromExtension(protocol)) {
mimeList = KMimeTypeRepository::self()->findFromFileName(fileName);
if (mimeList.size() == 1) {
if (accuracy) {
*accuracy = 50;
}
return mime;
return KMimeType::mimeType(mimeList.at(0));
}
}
// Try the magic matches
if (!fast_mode && is_local) {
QFile file(localfile);
if (file.open(QIODevice::ReadOnly)) {
int magicAccuracy = 0;
KMimeType::Ptr mime = KMimeTypeRepository::self()->findFromContent(&file, &magicAccuracy);
// mime can't be 0, except in case of install problems.
// However we get magicAccuracy==0 for octet-stream, i.e. no magic match found.
//kDebug(servicesDebugArea()) << "findFromContent said" << (mime?mime->name():QString()) << "with accuracy" << magicAccuracy;
if (mime && magicAccuracy > 0) {
// Disambiguate conflicting extensions (if magic found something and the magicrule was <80)
if (magicAccuracy < 80 && !mimeList.isEmpty()) {
// "for glob_match in glob_matches:"
// "if glob_match is subclass or equal to sniffed_type, use glob_match"
const QString sniffedMime = mime->name();
foreach(const QString &m, mimeList) {
KMimeType::Ptr mimeFromPattern = KMimeType::mimeType(m);
//kDebug(servicesDebugArea()) << "sniffedMime=" << sniffedMime << "mimeFromPattern=" << mimeFromPattern->name();
if (mimeFromPattern && mimeFromPattern->is(sniffedMime)) {
// We have magic + pattern pointing to this, so it's a pretty good match
if (accuracy) {
*accuracy = 100;
}
return mimeFromPattern;
}
}
}
if (accuracy) {
*accuracy = magicAccuracy;
}
return mime;
}
}
}
KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(protocol);
if (prot) {
const QString protmime = prot->defaultMimeType();
if (!protmime.isEmpty()) {
// Find a fallback from the protocol
if (accuracy) {
*accuracy = 10;
}
return KMimeType::mimeType(protmime);
}
}
if (accuracy) {
*accuracy = 0;
}
return defaultMimeTypePtr();
return KMimeType::defaultMimeTypePtr();
}
KMimeType::Ptr KMimeType::findByUrl(const KUrl& url, mode_t mode,
bool is_local_file, bool fast_mode,
int *accuracy)
KMimeType::Ptr KMimeType::findByName(const QString &fileName, int *accuracy)
{
if (!is_local_file && url.isLocalFile()) {
is_local_file = true;
}
if (is_local_file && !fast_mode) {
QFile file(url.toLocalFile());
return findByUrlHelper(url, mode, is_local_file, &file, accuracy);
}
return findByUrlHelper(url, mode, is_local_file, nullptr, accuracy);
return findByUrl(KUrl(fileName), 0, true, accuracy);
}
KMimeType::Ptr KMimeType::findByPath(const QString &path, mode_t mode,
bool fast_mode, int* accuracy)
KMimeType::Ptr KMimeType::findByContent(const QByteArray &data, int *accuracy)
{
KUrl url;
url.setPath(path);
return findByUrl(url, mode, true, fast_mode, accuracy);
}
KMimeType::Ptr KMimeType::findByNameAndContent(const QString &name, const QByteArray &data,
mode_t mode, int* accuracy)
{
KUrl url;
url.setPath(name);
KMimeTypeRepository::self()->checkEssentialMimeTypes();
QBuffer buffer(const_cast<QByteArray *>(&data));
return findByUrlHelper(url, mode, false, &buffer, accuracy);
}
KMimeType::Ptr KMimeType::findByNameAndContent(const QString &name, QIODevice *device,
mode_t mode, int* accuracy)
{
KUrl url;
url.setPath(name);
return findByUrlHelper(url, mode, false, device, accuracy);
buffer.open(QIODevice::ReadOnly);
return KMimeTypeRepository::self()->findFromContent(&buffer, accuracy);
}
QString KMimeType::extractKnownExtension(const QString &fileName)
@ -408,41 +293,6 @@ QString KMimeType::extractKnownExtension(const QString &fileName)
return pattern;
}
KMimeType::Ptr KMimeType::findByContent(const QByteArray &data, int *accuracy)
{
QBuffer buffer(const_cast<QByteArray *>(&data));
buffer.open(QIODevice::ReadOnly);
return KMimeTypeRepository::self()->findFromContent(&buffer, accuracy);
}
KMimeType::Ptr KMimeType::findByContent(QIODevice *device, int *accuracy)
{
return KMimeTypeRepository::self()->findFromContent(device, accuracy);
}
KMimeType::Ptr KMimeType::findByFileContent(const QString &fileName, int *accuracy)
{
KMimeTypeRepository::self()->checkEssentialMimeTypes();
QFile device(fileName);
// Look at mode first
KMimeType::Ptr mimeFromMode = findFromMode(fileName, 0, true);
if (mimeFromMode) {
if (accuracy) {
*accuracy = 100;
}
return mimeFromMode;
}
if (!device.open(QIODevice::ReadOnly)) {
if (accuracy) {
*accuracy = 0;
}
return KMimeType::defaultMimeTypePtr();
}
return KMimeTypeRepository::self()->findFromContent(&device, accuracy);
}
bool KMimeType::isBinaryData(const QString &fileName)
{
QFile file(fileName);
@ -453,22 +303,9 @@ bool KMimeType::isBinaryData(const QString &fileName)
return isBufferBinaryData(file.read(32));
}
KMimeType::KMimeType(const QString &fullpath, const QString &name)
: QSharedData(),
d_ptr(new KMimeTypePrivate(fullpath))
{
d_ptr->m_strName = name;
}
KMimeType::~KMimeType()
{
delete d_ptr;
}
QString KMimeType::iconNameForUrl(const KUrl &_url, mode_t mode)
{
const KMimeType::Ptr mt = findByUrl(_url, mode, _url.isLocalFile(), false /*HACK*/);
const KMimeType::Ptr mt = findByUrl(_url, mode);
if (!mt) {
return QString();
}

View file

@ -84,9 +84,8 @@ public:
static QString favIconForUrl(const KUrl &url, bool download = false);
/**
* Returns the descriptive comment associated with the MIME type.
* The url argument is unused, but provided so that KMimeType derived classes
* can use it.
* Returns the descriptive comment associated with the MIME type. The url argument is used for
* folders.
*
* @return The descriptive comment associated with the MIME type, if any.
*/
@ -114,83 +113,39 @@ public:
*
* @param name the name of the mime type
* @param options controls how the mime type is searched for
* @return the pointer to the KMimeType with the given @p name, or
* 0 if not found
* @return the pointer to the KMimeType with the given @p name or null if not found
* @see KServiceType::serviceType
*/
static Ptr mimeType(const QString &name, FindByNameOption options = ResolveAliases);
/**
* Finds a KMimeType with the given @p url.
* This function looks at mode_t first.
* If that does not help it looks at the extension (and the contents, for local files).
* This method is fine for many protocols like ftp, file, fish, zip etc.,
* but is not for http (e.g. cgi scripts
* make extension-based checking unreliable).
* For HTTP you should use KRun instead (to open the URL, in an app
* or internally), or a KIO::mimetype() job (to find the mimetype without
* downloading), or a KIO::get() job (to find the mimetype and then download).
* In fact KRun is the most complete solution, but deriving from it just
* for this is a bit cumbersome.
*
* If no extension matches, then the file contents will be examined if the URL is a local file, or
* "application/octet-stream" is returned otherwise.
*
* @param url Is the right most URL with a filesystem protocol. It
* is up to you to find out about that if you have a nested
* URL. For example
* "http://localhost/mist.gz#gzip:/decompress" would have to
* pass the "http://..." URL part, while
* "file:/tmp/x.tar#tar:/src/test.gz#gzip:/decompress" would
* have to pass the "tar:/..." part of the URL, since gzip is
* a filter protocol and not a filesystem protocol.
* @param mode the mode of the file (used, for example, to identify
* executables)
* @param is_local_file true if the file is local; false if not, or if you don't know.
* @param fast_mode If set to true no disk access is allowed to
* find out the mimetype. The result may be suboptimal, but
* it is @em fast.
* @param accuracy if set, the accuracy of the result, between 0 and 100.
* For instance, when the extension was used to determine the mimetype,
* the accuracy is set to 80, as per the shared-mime spec.
* Some 'magic' rules (used when !fast_mode) have an accuracy > 80
* (and have priority over the filename, others are < 80).
*
* @return A pointer to the matching mimetype. 0 is never returned.
* @em Very @em Important: Don't store the result in a KMimeType* !
*/
static Ptr findByUrl(const KUrl &url, mode_t mode = 0,
bool is_local_file = false, bool fast_mode = false,
int *accuracy = 0);
/**
* Finds a KMimeType with the given @p url.
* This function looks at mode_t first.
* If that does not help it
* looks at the extension. This is fine for FTP, FILE, TAR and
* friends, but is not for HTTP ( cgi scripts! ). You should use
* KRun instead, but this function returns immediately while
* KRun is async. If no extension matches, then
* the file contents will be examined if the URL is a local file, or
* "application/octet-stream" is returned otherwise.
*
* Equivalent to
* \code
* KUrl u(path);
* return findByUrl( u, mode, true, fast_mode );
* \endcode
* Finds a KMimeType with the given @p url. This function looks at mode_t first, if that does
* not help it looks at the name. If no extension matches, then the file contents will be
* examined if the URL is a local file. If nothing matches "application/octet-stream" is
* returned.
*
* @param path the path to the file (a file name is enough, in fast mode)
* @param mode the mode of the file (used, for example, to identify
* executables)
* @param fast_mode If set to true no disk access is allowed to
* find out the mimetype. The result may be suboptimal, but
* it is @em fast.
* @param mode the mode of the file (used, for example, to identify executables)
* @param fast_mode If set to true no disk access is allowed to find out the mimetype. The
* result may be suboptimal but it is @em fast.
* @param accuracy If not a null pointer accuracy is set to the accuracy of the match (which is
* in the range 0..100)
* @return A pointer to the matching mimetype. null is never returned.
*/
static Ptr findByUrl(const KUrl &url, mode_t mode = 0,
bool fast_mode = false, int* accuracy = 0);
/**
* Tries to find out the MIME type of a file by matching its name to MIME type rules. Note that
* the file's contents is not used.
*
* @param fileName the path to the file
* @param accuracy If not a null pointer, *accuracy is set to the
* accuracy of the match (which is in the range 0..100)
* @return A pointer to the matching mimetype. 0 is never returned.
* @return a pointer to the KMimeType, or the default mimetype
* (application/octet-stream) if the file cannot be opened.
*/
static Ptr findByPath(const QString &path, mode_t mode = 0,
bool fast_mode = false, int* accuracy = 0);
static Ptr findByName(const QString &fileName, int *accuracy = 0);
/**
* Tries to find out the MIME type of a data chunk by looking for
@ -202,74 +157,7 @@ public:
* @return a pointer to the KMimeType. "application/octet-stream" is
* returned if the type can not be found this way.
*/
static Ptr findByContent(const QByteArray &data, int *accuracy=0);
/**
* Tries to find out the MIME type of filename/url and a data chunk.
* Whether to trust the extension or the data depends on the results of both approaches,
* and is determined automatically.
*
* This method is useful for instance in the get() method of kioslaves, and anywhere else
* where a filename is associated with some data which is available immediately.
*
* @param name the filename or url representing this data.
* Only used for the extension, not used as a local filename.
* @param data the data to examine when the extension isn't conclusive in itself
* @param mode the mode of the file (used, for example, to identify executables)
* @param accuracy If not a null pointer, *accuracy is set to the
* accuracy of the match (which is in the range 0..100)
*/
static Ptr findByNameAndContent(const QString &name, const QByteArray &data,
mode_t mode = 0, int *accuracy = 0);
/**
* Tries to find out the MIME type of a data chunk by looking for
* certain magic numbers and characteristic strings in it.
*
* @param device the IO device providing the data to examine
* @param accuracy If not a null pointer, *accuracy is set to the
* accuracy of the match (which is in the range 0..100)
* @return a pointer to the KMimeType. "application/octet-stream" is
* returned if the type can not be found this way.
* @since 4.4
*/
static Ptr findByContent(QIODevice* device, int* accuracy = 0);
/**
* Tries to find out the MIME type of filename/url and a data chunk.
* Whether to trust the extension or the data depends on the results of both approaches,
* and is determined automatically.
*
* This method is useful for instance in the get() method of kioslaves, and anywhere else
* where a filename is associated with some data which is available immediately.
*
* @param name the filename or url representing this data.
* Only used for the extension, not used as a local filename.
* @param device the IO device providing the data to examine when the extension isn't conclusive in itself
* @param mode the mode of the file (used, for example, to identify executables)
* @param accuracy If not a null pointer, *accuracy is set to the
* accuracy of the match (which is in the range 0..100)
* @return a pointer to the KMimeType. "application/octet-stream" is
* returned if the type can not be found this way.
* @since 4.4
*/
static Ptr findByNameAndContent(const QString &name, QIODevice *device,
mode_t mode = 0, int* accuracy = 0);
/**
* Tries to find out the MIME type of a file by looking for
* certain magic numbers and characteristic strings in it.
* This function is similar to the previous one. Note that the
* file name is not used for determining the file type, it is just
* used for loading the file's contents.
*
* @param fileName the path to the file
* @param accuracy If not a null pointer, *accuracy is set to the
* accuracy of the match (which is in the range 0..100)
* @return a pointer to the KMimeType, or the default mimetype
* (application/octet-stream) if the file cannot be opened.
*/
static Ptr findByFileContent(const QString &fileName, int *accuracy = 0);
static Ptr findByContent(const QByteArray &data, int *accuracy = 0);
/**
* Returns whether a file has an internal format that is not human readable.
@ -414,9 +302,6 @@ protected:
private:
KMimeTypePrivate* d_ptr;
static KMimeType::Ptr findByUrlHelper(const KUrl &url, mode_t mode,
bool is_local_file, QIODevice* device, int* accuracy);
};
#endif // KMIMETYPE_H

View file

@ -274,7 +274,7 @@ void KMimeTypeTest::testFindByPathUsingFileName()
{
QFETCH(QString, fileName);
QFETCH(QString, expectedMimeType);
KMimeType::Ptr mime = KMimeType::findByPath(fileName);
KMimeType::Ptr mime = KMimeType::findByUrl(KUrl(fileName));
QVERIFY( mime );
QCOMPARE(mime->name(), expectedMimeType);
@ -314,14 +314,14 @@ void KMimeTypeTest::testFindByPathWithContent()
// If we find x-matlab because it starts with '%' then we are not ordering by priority.
KTemporaryFile tempFile;
QVERIFY(tempFile.open());
QString tempFileName = tempFile.fileName();
KUrl tempFileName = tempFile.fileName();
tempFile.write("%PDF-");
tempFile.close();
mime = KMimeType::findByPath( tempFileName );
mime = KMimeType::findByUrl( tempFileName );
QVERIFY( mime );
QCOMPARE( mime->name(), QString::fromLatin1( "application/pdf" ) );
// fast mode cannot find the mimetype
mime = KMimeType::findByPath( tempFileName, 0, true );
mime = KMimeType::findByUrl( tempFileName, 0, true );
QVERIFY( mime );
QCOMPARE(mime->name(), QString::fromLatin1("application/octet-stream"));
@ -331,13 +331,13 @@ void KMimeTypeTest::testFindByPathWithContent()
txtTempFile.setSuffix(".txt");
QVERIFY(txtTempFile.open());
txtTempFile.write("%PDF-");
QString txtTempFileName = txtTempFile.fileName();
KUrl txtTempFileName = txtTempFile.fileName();
txtTempFile.close();
mime = KMimeType::findByPath( txtTempFileName );
mime = KMimeType::findByUrl( txtTempFileName );
QVERIFY( mime );
QCOMPARE( mime->name(), QString::fromLatin1( "text/plain" ) );
// fast mode finds the same
mime = KMimeType::findByPath( txtTempFileName, 0, true );
mime = KMimeType::findByUrl( txtTempFileName, 0, true );
QVERIFY( mime );
QCOMPARE( mime->name(), QString::fromLatin1( "text/plain" ) );
}
@ -350,9 +350,9 @@ void KMimeTypeTest::testFindByPathWithContent()
txtTempFile.setSuffix(".txt");
QVERIFY(txtTempFile.open());
txtTempFile.write("<smil");
QString txtTempFileName = txtTempFile.fileName();
KUrl txtTempFileName = txtTempFile.fileName();
txtTempFile.close();
mime = KMimeType::findByPath( txtTempFileName );
mime = KMimeType::findByUrl( txtTempFileName );
QVERIFY( mime );
QCOMPARE( mime->name(), QString::fromLatin1( "text/plain" ) );
}
@ -374,63 +374,6 @@ void KMimeTypeTest::testFindByUrl()
QCOMPARE( mime->name(), QString::fromLatin1( "application/octet-stream" ) ); // HTTP can't know before downloading
}
void KMimeTypeTest::testFindByNameAndContent()
{
KMimeType::Ptr mime;
QByteArray textData = "Hello world";
// textfile -> text/plain. No extension -> mimetype is found from the contents.
mime = KMimeType::findByNameAndContent("textfile", textData);
QVERIFY( mime );
QCOMPARE( mime->name(), QString::fromLatin1("text/plain") );
// textfile.foo -> text/plain. Unknown extension -> mimetype is found from the contents.
mime = KMimeType::findByNameAndContent("textfile.foo", textData);
QVERIFY( mime );
QCOMPARE( mime->name(), QString::fromLatin1("text/plain") );
// mswordfile.doc -> application/msword. Found by glob.
mime = KMimeType::findByNameAndContent("textfile.doc", textData);
QVERIFY( mime );
QCOMPARE( mime->name(), QString::fromLatin1("application/msword") );
// mswordfile.doc -> application/msword. Found by contents.
// Note that it's application/msword, not application/vnd.ms-word, since it's the former that is registered to IANA.
QByteArray mswordData = "\320\317\021\340\241\261\032\341";
mime = KMimeType::findByNameAndContent("mswordfile.doc", mswordData);
QVERIFY( mime );
// If you get powerpoint instead, then you're hit by https://bugs.freedesktop.org/show_bug.cgi?id=435 - upgrade to shared-mime-info >= 0.22
QCOMPARE( mime->name(), QString::fromLatin1("application/msword") );
// excelfile.xls -> application/vnd.ms-excel. Found by extension.
mime = KMimeType::findByNameAndContent("excelfile.xls", mswordData /*same magic*/);
QVERIFY( mime );
QCOMPARE( mime->name(), QString::fromLatin1("application/vnd.ms-excel") );
// textfile.xls -> application/vnd.ms-excel. Found by extension. User shouldn't rename a text file to .xls ;)
mime = KMimeType::findByNameAndContent("textfile.xls", textData);
QVERIFY( mime );
QCOMPARE( mime->name(), QString::fromLatin1("application/vnd.ms-excel") );
#if 0 // needs shared-mime-info >= 0.20
QByteArray tnefData = "\x78\x9f\x3e\x22";
mime = KMimeType::findByNameAndContent("tneffile", mswordData);
QVERIFY( mime );
QCOMPARE( mime->name(), QString::fromLatin1("application/vnd.ms-tnef") );
#endif
QByteArray pdfData = "%PDF-";
mime = KMimeType::findByNameAndContent("foo", pdfData);
QVERIFY( mime );
QCOMPARE( mime->name(), QString::fromLatin1("application/pdf") );
// High-priority rule (80)
QByteArray phpData = "<?php";
mime = KMimeType::findByNameAndContent("foo", phpData);
QVERIFY( mime );
QCOMPARE( mime->name(), QString::fromLatin1("application/x-php") );
}
void KMimeTypeTest::testFindByContent_data()
{
QTest::addColumn<QByteArray>("data");
@ -464,20 +407,20 @@ void KMimeTypeTest::testFindByContent()
QCOMPARE( mime->name(), expectedMimeType );
}
void KMimeTypeTest::testFindByFileContent()
void KMimeTypeTest::testFindByName()
{
KMimeType::Ptr mime;
int accuracy = 0;
// Calling findByContent on a directory
mime = KMimeType::findByFileContent("/", &accuracy);
// Calling findByName on a directory
mime = KMimeType::findByName("/", &accuracy);
QVERIFY(mime);
QCOMPARE(mime->name(), QString::fromLatin1("inode/directory"));
QCOMPARE(accuracy, 100);
// Albert calls findByFileContent with a URL instead of a path and gets 11021 as accuracy :)
// It was not set inside findByFileContent -> fixed.
mime = KMimeType::findByFileContent("file:///etc/passwd" /*bad example code, use a path instead*/, &accuracy);
// Albert calls findByName with a URL instead of a path and gets 11021 as accuracy :)
// It was not set inside findByName -> fixed.
mime = KMimeType::findByName("file:///etc/passwd" /*bad example code, use a path instead*/, &accuracy);
QVERIFY(mime);
QCOMPARE(mime->name(), QString::fromLatin1("application/octet-stream"));
QCOMPARE(accuracy, 0);
@ -954,15 +897,14 @@ void KMimeTypeTest::testThreads()
{
// Note that data-based tests cannot be used here (QTest::fetchData asserts).
std::future<void> future1 = std::async(std::launch::async, &KMimeTypeTest::testFindByUrl, this);
std::future<void> future2 = std::async(std::launch::async, &KMimeTypeTest::testFindByFileContent, this);
std::future<void> future3 = std::async(std::launch::async, &KMimeTypeTest::testFindByNameAndContent, this);
std::future<void> future4 = std::async(std::launch::async, &KMimeTypeTest::testFindByPathWithContent, this);
std::future<void> future5 = std::async(std::launch::async, &KMimeTypeTest::testAllMimeTypes, this);
std::future<void> future6 = std::async(std::launch::async, &KMimeTypeTest::testAlias, this);
std::future<void> future7 = std::async(std::launch::async, &KMimeTypeTest::testMimeTypeParent, this);
std::future<void> future8 = std::async(std::launch::async, &KMimeTypeTest::testPreferredService, this);
std::future<void> future9 = std::async(std::launch::async, &KMimeTypeTest::testFromThread, this);
std::future<void> future10 = std::async(std::launch::async, &KMimeTypeTest::testHelperProtocols, this);
std::future<void> future2 = std::async(std::launch::async, &KMimeTypeTest::testFindByName, this);
std::future<void> future3 = std::async(std::launch::async, &KMimeTypeTest::testFindByPathWithContent, this);
std::future<void> future4 = std::async(std::launch::async, &KMimeTypeTest::testAllMimeTypes, this);
std::future<void> future5 = std::async(std::launch::async, &KMimeTypeTest::testAlias, this);
std::future<void> future6 = std::async(std::launch::async, &KMimeTypeTest::testMimeTypeParent, this);
std::future<void> future7 = std::async(std::launch::async, &KMimeTypeTest::testPreferredService, this);
std::future<void> future8 = std::async(std::launch::async, &KMimeTypeTest::testFromThread, this);
std::future<void> future9 = std::async(std::launch::async, &KMimeTypeTest::testHelperProtocols, this);
kDebug() << "Joining all threads";
future1.wait();
future2.wait();
@ -973,7 +915,6 @@ void KMimeTypeTest::testThreads()
future7.wait();
future8.wait();
future9.wait();
future10.wait();
}
#include "moc_kmimetypetest.cpp"

View file

@ -38,10 +38,9 @@ private Q_SLOTS:
void testAdditionalGlobs_data();
void testAdditionalGlobs();
void testFindByPathWithContent();
void testFindByNameAndContent();
void testFindByContent();
void testFindByContent_data();
void testFindByFileContent();
void testFindByName();
void testAllMimeTypes();
void testAlias();
void testMimeTypeParent();

View file

@ -35,7 +35,7 @@ static bool kCheckMimeData(const QMimeData *mimedata)
return true;
} else if (mimedata->hasUrls()) {
foreach (const QUrl &mimedataurl, mimedata->urls()) {
const KMimeType::Ptr mimetype = KMimeType::findByPath(mimedataurl.toLocalFile());
const KMimeType::Ptr mimetype = KMimeType::findByUrl(mimedataurl);
if (mimetype && KImageIO::isSupported(mimetype->name())) {
// atleast one supported image
return true;
@ -191,10 +191,9 @@ void KPixmapWidget::dropEvent(QDropEvent *event)
setPixmap(qvariant_cast<QPixmap>(mimedata->imageData()));
} else if (mimedata->hasUrls()) {
foreach (const QUrl &mimedataurl, mimedata->urls()) {
const QString mimedataurlpath = mimedataurl.toLocalFile();
const KMimeType::Ptr mimetype = KMimeType::findByPath(mimedataurlpath);
const KMimeType::Ptr mimetype = KMimeType::findByUrl(mimedataurl);
if (mimetype && KImageIO::isSupported(mimetype->name())) {
const QPixmap mimedataurlpixmap = QPixmap(mimedataurlpath);
const QPixmap mimedataurlpixmap = QPixmap(mimedataurl.toLocalFile());
if (!mimedataurlpixmap.isNull()) {
// the last pixmap wins
setPixmap(mimedataurlpixmap.scaled(QWidget::size(), Qt::KeepAspectRatio));

View file

@ -1323,7 +1323,7 @@ bool KDirOperator::Private::checkPreviewInternal() const
return true;
}
KMimeType::Ptr mt = KMimeType::findByPath(it1, 0, true /*fast mode, no file contents exist*/);
KMimeType::Ptr mt = KMimeType::findByUrl(KUrl(it1), 0, true /*fast mode, no file contents exist*/);
if (!mt)
continue;
const QString mime = mt->name();

View file

@ -2246,7 +2246,7 @@ void KFileWidgetPrivate::updateFilter()
return;
if( filterWidget->isMimeFilter()) {
KMimeType::Ptr mime = KMimeType::findByPath(urlStr, 0, true);
KMimeType::Ptr mime = KMimeType::findByUrl(KUrl(urlStr));
if (mime && mime->name() != KMimeType::defaultMimeType()) {
if (filterWidget->currentFilter() != mime->name() &&
filterWidget->filters().indexOf(mime->name()) != -1)

View file

@ -527,7 +527,10 @@ void KNewFileMenuPrivate::executeStrategy()
QFile srcFile(uSrc.toLocalFile());
if (srcFile.open(QIODevice::ReadOnly)) {
KMimeType::Ptr wantedMime = KMimeType::findByUrl(uSrc);
KMimeType::Ptr mime = KMimeType::findByNameAndContent(m_copyData.m_chosenFileName, &srcFile);
KMimeType::Ptr mime = KMimeType::findByName(m_copyData.m_chosenFileName);
if (mime && mime->isDefault()) {
mime = wantedMime;
}
// kDebug() << "mime=" << mime->name() << "wantedMime=" << wantedMime->name();
if (!mime->is(wantedMime->name()))
chosenFileName += wantedMime->mainExtension();
@ -633,7 +636,7 @@ void KNewFileMenuPrivate::fillMenu()
// Determine mimetype on demand
KMimeType::Ptr mime;
if (entry.mimeType.isEmpty()) {
mime = KMimeType::findByPath(entry.templatePath);
mime = KMimeType::findByUrl(KUrl(entry.templatePath));
if (mime) {
// kDebug() << entry.templatePath << "is" << mime->name();
entry.mimeType = mime->name();

View file

@ -698,7 +698,7 @@ KFilePropsPlugin::KFilePropsPlugin(KPropertiesDialog *props)
KIO::filesize_t totalSize = item.size();
QString magicMimeComment;
if (isLocal) {
KMimeType::Ptr magicMimeType = KMimeType::findByFileContent(url.toLocalFile());
KMimeType::Ptr magicMimeType = KMimeType::findByUrl(url);
if (magicMimeType->name() != KMimeType::defaultMimeType()) {
magicMimeComment = magicMimeType->comment();
}
@ -800,7 +800,7 @@ KFilePropsPlugin::KFilePropsPlugin(KPropertiesDialog *props)
mimeComment.clear();
}
if (isLocal && !magicMimeComment.isNull()) {
KMimeType::Ptr magicMimeType = KMimeType::findByFileContent(url.toLocalFile());
KMimeType::Ptr magicMimeType = KMimeType::findByUrl(url);
if (magicMimeType->comment() != magicMimeComment) {
magicMimeComment.clear();
}
@ -1421,9 +1421,7 @@ void KFilePropsPlugin::applyIconChanges()
}
// Get the default image
QString str = KMimeType::findByUrl(url,
properties->item().mode(),
true )->iconName();
QString str = KMimeType::findByUrl(url, properties->item().mode())->iconName();
// Is it another one than the default ?
QString sIcon;
if (str != iconButton->icon()) {

View file

@ -603,7 +603,7 @@ KMimeType::Ptr KFileItem::determineMimeType() const
if (!d->m_pMimeType || !d->m_bMimeTypeKnown) {
bool isLocalUrl = false;
KUrl url = mostLocalUrl(isLocalUrl);
d->m_pMimeType = KMimeType::findByUrl(url, d->m_fileMode, isLocalUrl);
d->m_pMimeType = KMimeType::findByUrl(url, d->m_fileMode, !isLocalUrl);
Q_ASSERT(d->m_pMimeType);
// kDebug() << d << "finding final mimetype for" << url << ":" << d->m_pMimeType->name();
d->m_bMimeTypeKnown = true;
@ -871,7 +871,7 @@ QPixmap KFileItem::pixmap(int _size, int _state) const
KUrl sf;
sf.setPath(d->m_url.path().left( d->m_url.path().length() - 3));
// kDebug() << "subFileName=" << subFileName;
mime = KMimeType::findByUrl(sf, 0, d->m_bIsLocalUrl);
mime = KMimeType::findByUrl(sf, 0, !d->m_bIsLocalUrl);
}
KUrl url = mostLocalUrl();
@ -1316,13 +1316,12 @@ KMimeType::Ptr KFileItem::mimeTypePtr() const
Q_ASSERT(!d->m_url.isEmpty());
bool isLocalUrl = false;
KUrl url = mostLocalUrl(isLocalUrl);
int accuracy;
d->m_pMimeType = KMimeType::findByUrl(
url, d->m_fileMode, isLocalUrl,
url, d->m_fileMode,
// use fast mode if delayed mimetype determination can refine it later
d->m_delayedMimeTypes, &accuracy
d->m_delayedMimeTypes
);
// If we didn't get a perfect (glob and content-based) match,
// If it was not a perfect (glob and content-based) match,
// then determineMimeType will be able to do better for readable URLs.
const bool canDoBetter = d->m_delayedMimeTypes;
//kDebug() << "finding mimetype for" << url << ":" << d->m_pMimeType->name() << "canDoBetter=" << canDoBetter;

View file

@ -1071,7 +1071,7 @@ void KRun::init()
d->m_mode = buff.st_mode;
}
KMimeType::Ptr mime = KMimeType::findByUrl(d->m_strURL, d->m_mode, true /*local*/);
KMimeType::Ptr mime = KMimeType::findByUrl(d->m_strURL, d->m_mode);
assert(mime);
kDebug(7010) << "MIME TYPE is " << mime->name();
if (mime->isDefault() && !QFileInfo(d->m_strURL.toLocalFile()).isReadable()) {

View file

@ -652,9 +652,13 @@ bool FileProtocol::createUDSEntry(const QString &filename, const QByteArray &pat
notype:
if (details > 1) {
QString fullPath = QFile::decodeName(path);
if (!fullPath.startsWith(QDir::separator())) {
fullPath.prepend(QDir::currentPath() + QDir::separator());
}
// In real "remote" slaves, this usually depends on the protocol but not here - it can be
// determined from content, path or mode
KMimeType::Ptr mt = KMimeType::findByPath(QFile::decodeName(path), buff.st_mode);
KMimeType::Ptr mt = KMimeType::findByUrl(KUrl(fullPath), type);
if (!mt.isNull()) {
entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, mt->name());
}

View file

@ -451,7 +451,7 @@ bool ReadOnlyPartPrivate::openLocalFile()
// set the mimetype only if it was not already set (for example, by the host application)
if (m_arguments.mimeType().isEmpty()) {
// get the mimetype of the file using findByUrl() to avoid another string -> url conversion
KMimeType::Ptr mime = KMimeType::findByUrl(m_url, 0, true /* local file*/);
KMimeType::Ptr mime = KMimeType::findByUrl(m_url);
if (mime) {
m_arguments.setMimeType(mime->name());
m_bAutoDetectedMime = true;

View file

@ -458,7 +458,7 @@ KArchive::KArchive(const QString &path, QObject *parent)
return;
}
const KMimeType::Ptr kmimetype = KMimeType::findByPath(path);
const KMimeType::Ptr kmimetype = KMimeType::findByUrl(KUrl(path));
if (kmimetype) {
foreach (const QString &mime, KArchive::writableMimeTypes()) {
if (kmimetype->is(mime)) {

View file

@ -267,7 +267,7 @@ KCompressor::KCompressorType KCompressor::typeForMime(const QString &mime)
KCompressor::KCompressorType KCompressor::typeForFile(const QString &filepath)
{
const KMimeType::Ptr kmimetype = KMimeType::findByPath(filepath);
const KMimeType::Ptr kmimetype = KMimeType::findByUrl(KUrl(filepath));
if (kmimetype) {
return KCompressor::typeForMime(kmimetype->name());
}

View file

@ -64,7 +64,7 @@ public:
@note By default the type is none (i.e. @p KCompressorType::TypeUnknown). The type must be
set before processing data and can determined via @p KCompressor::typeForMime or
@p KCompressor::typeForFile depending if the input is file or data in memory
@see KMimeType::findByPath, KMimeType::findByContent
@see KMimeType::findByUrl, KMimeType::findByContent
*/
bool setType(const KCompressorType type);
/*!

View file

@ -305,7 +305,7 @@ KDecompressor::KDecompressorType KDecompressor::typeForMime(const QString &mime)
KDecompressor::KDecompressorType KDecompressor::typeForFile(const QString &filepath)
{
const KMimeType::Ptr kmimetype = KMimeType::findByPath(filepath);
const KMimeType::Ptr kmimetype = KMimeType::findByUrl(KUrl(filepath));
if (kmimetype) {
return KDecompressor::typeForMime(kmimetype->name());
}

View file

@ -63,7 +63,7 @@ public:
@note By default the type is none (i.e. @p KDecompressorType::TypeUnknown). The type must be
set before processing data and can determined via @p KDecompressor::typeForMime or
@p KDecompressor::typeForFile depending if the input is file or data in memory
@see KMimeType::findByPath, KMimeType::findByContent
@see KMimeType::findByUrl, KMimeType::findByContent
*/
bool setType(const KDecompressorType type);

View file

@ -477,7 +477,7 @@ bool KAbstractPlayer::isProtocolSupported(const QString &protocol) const
bool KAbstractPlayer::isPathSupported(const QString &path) const
{
const KMimeType::Ptr mime = KMimeType::findByPath(path);
const KMimeType::Ptr mime = KMimeType::findByUrl(KUrl(path));
if (mime && isMimeSupported(mime->name())) {
return true;
}

View file

@ -54,7 +54,7 @@ public:
return;
}
KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
KMimeType::Ptr mime = KMimeType::findByUrl(KUrl(absImagePath));
QPixmap pm(q->size().toSize());
if (mime->is("image/svg+xml") || mime->is("image/svg+xml-compressed")) {

View file

@ -174,7 +174,7 @@ void Frame::setImage(const QString &path)
return;
}
KMimeType::Ptr mime = KMimeType::findByPath(d->absImagePath);
KMimeType::Ptr mime = KMimeType::findByUrl(KUrl(d->absImagePath));
if (!mime->is("image/svg+xml") && !mime->is("application/x-gzip")) {
d->pixmap = new QPixmap(d->absImagePath);

View file

@ -62,7 +62,7 @@ public:
return;
}
KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
KMimeType::Ptr mime = KMimeType::findByUrl(KUrl(absImagePath));
QPixmap pm(q->size().toSize());
if (mime->is("image/svg+xml") || mime->is("image/svg+xml-compressed")) {

View file

@ -62,7 +62,7 @@ public:
return;
}
KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
KMimeType::Ptr mime = KMimeType::findByUrl(KUrl(absImagePath));
QPixmap pm;
if (mime->is("image/svg+xml") || mime->is("image/svg+xml-compressed")) {

View file

@ -52,7 +52,7 @@ public:
return;
}
KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
KMimeType::Ptr mime = KMimeType::findByUrl(KUrl(absImagePath));
QPixmap pm(q->size().toSize());
if (mime->is("image/svg+xml")) {

View file

@ -66,7 +66,7 @@ public:
return;
}
KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
KMimeType::Ptr mime = KMimeType::findByUrl(KUrl(absImagePath));
QPixmap pm;
if (mime->is("image/svg+xml") || mime->is("image/svg+xml-compressed")) {

View file

@ -52,7 +52,7 @@ public:
return;
}
KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
KMimeType::Ptr mime = KMimeType::findByUrl(KUrl(absImagePath));
QPixmap pm(q->size().toSize());
if (mime->is("image/svg+xml")) {