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(
"Icon") )
449 res.append( QString::fromLatin1(
"Patterns") );
450 res.append( QString::fromLatin1(
"Icon") );
472 || _url.
path().length() <= 1 )
480 if ( _url.
path().length() <= 1 && ( i == unknown || i.isEmpty() ) )
483 return !i.isEmpty() ? i : unknown;
496 static int autoClearCache = 0;
497 const QString notFound = QLatin1String(
"NOTFOUND");
500 || !url.
protocol().startsWith(QLatin1String(
"http"))
504 QString iconNameFromCache = iconNameCache.value(url, notFound);
505 if ( iconNameFromCache != notFound ) {
506 if ( (++autoClearCache) < 5000 ) {
507 return iconNameFromCache;
510 iconNameCache.clear();
515 QDBusInterface kded( QString::fromLatin1(
"org.kde.kded"),
516 QString::fromLatin1(
"/modules/favicons"),
517 QString::fromLatin1(
"org.kde.FavIcon") );
518 QDBusReply<QString> result = kded.call( QString::fromLatin1(
"iconForUrl"), url.
url() );
519 iconNameCache.insert(url, result.value());
526 return d->comment(url);
529 #ifndef KDE_NO_DEPRECATED
533 if (!parents.isEmpty())
534 return parents.first();
541 QStack<QString> toCheck;
543 while (!toCheck.isEmpty()) {
544 const QString current = toCheck.pop();
548 toCheck.push(parent);
557 if (
name() == mimeTypeName)
560 return d->inherits(mime);
572 Q_FOREACH(
const QString& parent, parents) {
574 if (!allParents.contains(parent))
575 allParents.append(parent);
579 Q_FOREACH(
const QString& parent, parents) {
589 if (!canonical.isEmpty())
590 allParents.append(canonical);
597 static const QString & s_strDefaultMimeType =
599 return s_strDefaultMimeType;
605 return d->iconName(url);
611 d->ensureXmlDataLoaded();
612 return d->m_lstPatterns;
625 if (mimeFiles.isEmpty()) {
626 kWarning() <<
"No file found for" << file <<
", even though the file appeared in a directory listing.";
627 kWarning() <<
"Either it was just removed, or the directory doesn't have executable permission...";
635 QString preferredLanguage = languageList.first();
638 QListIterator<QString> mimeFilesIter(mimeFiles);
639 mimeFilesIter.toBack();
640 while (mimeFilesIter.hasPrevious()) {
641 const QString fullPath = mimeFilesIter.previous();
642 QFile qfile(fullPath);
643 if (!qfile.open(QFile::ReadOnly))
646 QXmlStreamReader xml(&qfile);
647 if (xml.readNextStartElement()) {
648 if (xml.name() !=
"mime-type") {
651 const QString name = xml.attributes().value(QLatin1String(
"type")).toString();
655 kWarning() <<
"Got name" << name <<
"in file" << file <<
"expected" <<
m_strName;
658 while (xml.readNextStartElement()) {
659 const QStringRef tag = xml.name();
660 if (tag ==
"comment") {
661 QString lang = xml.attributes().value(QLatin1String(
"xml:lang")).toString();
662 const QString text = xml.readElementText();
663 if (lang.isEmpty()) {
664 lang = QLatin1String(
"en_US");
666 if (lang == preferredLanguage) {
669 commentsByLanguage.insert(lang, text);
672 }
else if (tag ==
"icon") {
673 m_iconName = xml.attributes().value(QLatin1String(
"name")).toString();
674 }
else if (tag ==
"glob-deleteall") {
677 }
else if (tag ==
"glob") {
678 const QString pattern = xml.attributes().value(QLatin1String(
"pattern")).toString();
679 if (mainPattern.isEmpty() && pattern.startsWith(QLatin1Char(
'*'))) {
680 mainPattern = pattern;
685 xml.skipCurrentElement();
687 if (xml.name() !=
"mime-type") {
688 kFatal() <<
"Programming error in KMimeType XML loading, please create a bug report on http://bugs.kde.org and attach the file" << fullPath;
693 if (comment.isEmpty()) {
694 Q_FOREACH(
const QString& lang, languageList) {
695 const QString comm = commentsByLanguage.value(lang);
696 if (!comm.isEmpty()) {
700 const int pos = lang.indexOf(QLatin1Char(
'_'));
703 const QString shortLang = lang.left(pos);
704 const QString comm = commentsByLanguage.value(shortLang);
705 if (!comm.isEmpty()) {
711 if (comment.isEmpty()) {
712 kWarning() <<
"Missing <comment> field in" << file;
719 if (!mainPattern.isEmpty() &&
m_lstPatterns.first() != mainPattern) {
733 d->ensureXmlDataLoaded();
734 return d->m_iconName;
746 #if 1 // HACK START - can be removed once shared-mime-info >= 0.70 is used/required.
750 static const struct {
const char* mime;
const char* extension; } s_hardcodedMimes[] = {
751 {
"text/plain",
".txt" } };
752 if (d->m_lstPatterns.count() > 1) {
753 const QByteArray me =
name().toLatin1();
754 for (uint i = 0; i <
sizeof(s_hardcodedMimes)/
sizeof(*s_hardcodedMimes); ++i) {
755 if (me == s_hardcodedMimes[i].mime)
756 return QString::fromLatin1(s_hardcodedMimes[i].extension);
764 if (pattern.startsWith(QLatin1String(
"*.")) &&
765 pattern.length() > 2 &&
766 pattern.indexOf(QLatin1Char(
'*'), 2) < 0 && pattern.indexOf(QLatin1Char(
'?'), 2) < 0) {
767 return pattern.mid(1);