27 #include <kdeversion.h>
34 #include <QtCore/QFile>
35 #include <QtDBus/QtDBus>
36 #include <QtCore/QHash>
53 void KMimeType::checkEssentialMimeTypes()
68 if (!mimeType.startsWith(QLatin1String(
"x-scheme-handler")))
77 const char* p = data.data();
78 const int end = qMin(32, data.size());
79 for (
int i = 0; i < end; ++i) {
80 if ((
unsigned char)(p[i]) < 32 && p[i] != 9 && p[i] != 10 && p[i] != 13)
90 if ( is_local_file && (mode == 0 || mode == (mode_t)-1) ) {
96 if ( S_ISDIR( mode ) ) {
109 if ( S_ISCHR( mode ) )
111 if ( S_ISBLK( mode ) )
113 if ( S_ISFIFO( mode ) )
115 if ( S_ISSOCK( mode ) )
119 int size = path.size();
120 if ( size == 2 || size == 3 ) {
123 unsigned int type = GetDriveTypeW( (LPCWSTR) path.utf16() );
125 case DRIVE_REMOVABLE:
144 if ( !is_local_file && S_ISREG( mode ) && ( mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) )
185 checkEssentialMimeTypes();
199 if ( !fileName.isEmpty() && !path.endsWith( QLatin1Char(
'/') ) ) {
201 if ( is_local_file || _url.
hasSubUrl() ||
206 if ( mimeList.count() == 1 ) {
207 const QString selectedMime = mimeList.at(0);
212 kWarning() <<
"Glob file refers to" << selectedMime <<
"but this mimetype does not exist!";
221 if ( device && !device->isOpen() ) {
222 if ( !device->open(QIODevice::ReadOnly) ) {
228 QByteArray beginning;
235 if (mime && magicAccuracy > 0) {
238 if (magicAccuracy < 80 && !mimeList.isEmpty()) {
242 foreach(
const QString &m, mimeList) {
245 if (mimeFromPattern && mimeFromPattern->
is(sniffedMime)) {
249 return mimeFromPattern;
255 *accuracy = magicAccuracy;
263 if (!mimeList.isEmpty()) {
268 qSort(mimeList.begin(), mimeList.end());
269 Q_FOREACH(
const QString& mimeName, mimeList) {
272 kWarning() <<
"Glob file refers to" << mimeName <<
"but this mimetype does not exist!";
286 def = prot->defaultMimeType();
293 if ( path.endsWith( QLatin1Char(
'/') ) || path.isEmpty() ) {
298 if ( def.isEmpty() ) {
301 if ( prot && prot->supportsListing() ) {
317 bool is_local_file,
bool fast_mode,
321 is_local_file =
true;
322 if (is_local_file && !fast_mode) {
324 return findByUrlHelper(url, mode, is_local_file, &file, accuracy);
326 return findByUrlHelper(url, mode, is_local_file, 0, accuracy);
330 bool fast_mode,
int* accuracy )
334 return findByUrl(url, mode,
true, fast_mode, accuracy);
338 mode_t mode,
int* accuracy )
342 QBuffer buffer(const_cast<QByteArray *>(&data));
343 return findByUrlHelper(url, mode,
false, &buffer, accuracy);
347 mode_t mode,
int* accuracy )
351 return findByUrlHelper(url, mode,
false, device, accuracy);
363 QBuffer buffer(const_cast<QByteArray *>(&data));
364 buffer.open(QIODevice::ReadOnly);
377 checkEssentialMimeTypes();
379 QFile device(fileName);
387 if (!device.open(QIODevice::ReadOnly)) {
399 QFile file(fileName);
400 if (!file.open(QIODevice::ReadOnly))
402 const QByteArray data = file.read(32);
438 if ( _name == QLatin1String(
"Patterns") )
440 if ( _name == QLatin1String(
"Comment") )
442 if ( _name == QLatin1String(
"Icon") )
451 res.append( QString::fromLatin1(
"Patterns") );
452 res.append( QString::fromLatin1(
"Icon") );
474 || _url.
path().length() <= 1 )
482 if ( _url.
path().length() <= 1 && ( i == unknown || i.isEmpty() ) )
485 return !i.isEmpty() ? i : unknown;
498 static int autoClearCache = 0;
499 const QString notFound = QLatin1String(
"NOTFOUND");
502 || !url.
protocol().startsWith(QLatin1String(
"http"))
506 QString iconNameFromCache = iconNameCache.value(url, notFound);
507 if ( iconNameFromCache != notFound ) {
508 if ( (++autoClearCache) < 5000 ) {
509 return iconNameFromCache;
512 iconNameCache.clear();
517 QDBusInterface kded( QString::fromLatin1(
"org.kde.kded"),
518 QString::fromLatin1(
"/modules/favicons"),
519 QString::fromLatin1(
"org.kde.FavIcon") );
520 QDBusReply<QString> result = kded.call( QString::fromLatin1(
"iconForUrl"), url.
url() );
521 iconNameCache.insert(url, result.value());
528 return d->comment(url);
531 #ifndef KDE_NO_DEPRECATED
535 if (!parents.isEmpty())
536 return parents.first();
543 QStack<QString> toCheck;
545 while (!toCheck.isEmpty()) {
546 const QString current = toCheck.pop();
550 toCheck.push(parent);
559 if (
name() == mimeTypeName)
562 return d->inherits(mime);
574 Q_FOREACH(
const QString& parent, parents) {
576 if (!allParents.contains(parent))
577 allParents.append(parent);
581 Q_FOREACH(
const QString& parent, parents) {
591 if (!canonical.isEmpty())
592 allParents.append(canonical);
599 static const QString & s_strDefaultMimeType =
601 return s_strDefaultMimeType;
607 return d->iconName(url);
613 return d->patterns();
626 if (mimeFiles.isEmpty()) {
627 kWarning() <<
"No file found for" << file <<
", even though the file appeared in a directory listing.";
628 kWarning() <<
"Either it was just removed, or the directory doesn't have executable permission...";
636 QString preferredLanguage = languageList.first();
639 QListIterator<QString> mimeFilesIter(mimeFiles);
640 mimeFilesIter.toBack();
641 while (mimeFilesIter.hasPrevious()) {
642 const QString fullPath = mimeFilesIter.previous();
643 QFile qfile(fullPath);
644 if (!qfile.open(QFile::ReadOnly))
647 QXmlStreamReader xml(&qfile);
648 if (xml.readNextStartElement()) {
649 if (xml.name() !=
"mime-type") {
652 const QString name = xml.attributes().value(QLatin1String(
"type")).toString();
656 kWarning() <<
"Got name" << name <<
"in file" << file <<
"expected" <<
m_strName;
659 while (xml.readNextStartElement()) {
660 const QStringRef tag = xml.name();
661 if (tag ==
"comment") {
662 QString lang = xml.attributes().value(QLatin1String(
"xml:lang")).toString();
663 const QString text = xml.readElementText();
664 if (lang.isEmpty()) {
665 lang = QLatin1String(
"en_US");
667 if (lang == preferredLanguage) {
670 commentsByLanguage.insert(lang, text);
673 }
else if (tag ==
"icon") {
674 m_iconName = xml.attributes().value(QLatin1String(
"name")).toString();
675 }
else if (tag ==
"glob-deleteall") {
678 }
else if (tag ==
"glob") {
679 const QString pattern = xml.attributes().value(QLatin1String(
"pattern")).toString();
680 if (mainPattern.isEmpty() && pattern.startsWith(QLatin1Char(
'*'))) {
681 mainPattern = pattern;
686 xml.skipCurrentElement();
688 if (xml.name() !=
"mime-type") {
689 kFatal() <<
"Programming error in KMimeType XML loading, please create a bug report on http://bugs.kde.org and attach the file" << fullPath;
694 if (comment.isEmpty()) {
695 Q_FOREACH(
const QString& lang, languageList) {
696 const QString comm = commentsByLanguage.value(lang);
697 if (!comm.isEmpty()) {
701 const int pos = lang.indexOf(QLatin1Char(
'_'));
704 const QString shortLang = lang.left(pos);
705 const QString comm = commentsByLanguage.value(shortLang);
706 if (!comm.isEmpty()) {
712 if (comment.isEmpty()) {
713 kWarning() <<
"Missing <comment> field in" << file;
720 if (!mainPattern.isEmpty() &&
m_lstPatterns.first() != mainPattern) {
734 d->ensureXmlDataLoaded();
735 return d->m_iconName;
747 #if 1 // HACK START - can be removed once shared-mime-info >= 0.70 is used/required.
751 static const struct {
const char* mime;
const char* extension; } s_hardcodedMimes[] = {
752 {
"text/plain",
".txt" } };
753 if (d->m_lstPatterns.count() > 1) {
754 const QByteArray me =
name().toLatin1();
755 for (uint i = 0; i <
sizeof(s_hardcodedMimes)/
sizeof(*s_hardcodedMimes); ++i) {
756 if (me == s_hardcodedMimes[i].mime)
757 return QString::fromLatin1(s_hardcodedMimes[i].extension);
765 if (pattern.startsWith(QLatin1String(
"*.")) &&
766 pattern.length() > 2 &&
767 pattern.indexOf(QLatin1Char(
'*'), 2) < 0 && pattern.indexOf(QLatin1Char(
'?'), 2) < 0) {
768 return pattern.mid(1);
789 if (!iconNameFromCache.isEmpty())
790 return iconNameFromCache;
801 const int slashindex = icon.indexOf(QLatin1Char(
'/'));
802 if (slashindex != -1) {
803 icon[slashindex] = QLatin1Char(
'-');