File indexing completed on 2023-09-24 04:04:53
0001 /* This file is part of the KDE libraries 0002 * Copyright (C) 1999 Waldo Bastian <bastian@kde.org> 0003 * 2000-2007 David Faure <faure@kde.org> 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Library General Public 0007 * License version 2 as published by the Free Software Foundation; 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Library General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Library General Public License 0015 * along with this library; see the file COPYING.LIB. If not, write to 0016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 **/ 0019 0020 #include "kmimetype.h" 0021 #include "kmimetype_p.h" 0022 #include "kmimetyperepository_p.h" 0023 #include "qmimedatabase.h" 0024 0025 #include <kdebug.h> 0026 #include <kde_file.h> // KDE::stat 0027 #include <kdeversion.h> // KDE_MAKE_VERSION 0028 #include <klocalizedstring.h> 0029 #include <qstandardpaths.h> 0030 #include <kurl.h> 0031 #include <kio/global.h> 0032 0033 #include <QFile> 0034 0035 #ifdef Q_OS_WIN 0036 #include <windows.h> 0037 #endif 0038 0039 #ifndef S_ISSOCK 0040 #define S_ISSOCK(x) false 0041 #endif 0042 0043 extern int servicesDebugArea(); 0044 0045 template class QExplicitlySharedDataPointer<KMimeType>; 0046 0047 KMimeType::Ptr KMimeType::defaultMimeTypePtr() 0048 { 0049 return KMimeTypeRepository::self()->defaultMimeTypePtr(); 0050 } 0051 0052 bool KMimeType::isDefault() const 0053 { 0054 return name() == defaultMimeType(); 0055 } 0056 0057 KMimeType::Ptr KMimeType::mimeType(const QString &name, FindByNameOption options) 0058 { 0059 Q_UNUSED(options); 0060 QMimeDatabase db; 0061 QMimeType mime = db.mimeTypeForName(name); 0062 if (mime.isValid()) { 0063 return KMimeType::Ptr(new KMimeType(mime)); 0064 } else { 0065 return KMimeType::Ptr(); 0066 } 0067 } 0068 0069 KMimeType::List KMimeType::allMimeTypes() 0070 { 0071 // This could be done faster... 0072 KMimeType::List lst; 0073 QMimeDatabase db; 0074 Q_FOREACH (const QMimeType &mimeType, db.allMimeTypes()) { 0075 Q_ASSERT(!mimeType.name().startsWith(QLatin1String("x-scheme-handler"))); 0076 lst.append(KMimeType::Ptr(new KMimeType(mimeType))); 0077 } 0078 return lst; 0079 } 0080 0081 // TODO used outside of kmimetype? 0082 bool KMimeType::isBufferBinaryData(const QByteArray &data) 0083 { 0084 // Check the first 32 bytes (see shared-mime spec) 0085 const char *p = data.data(); 0086 const int end = qMin(32, data.size()); 0087 for (int i = 0; i < end; ++i) { 0088 if ((unsigned char)(p[i]) < 32 && p[i] != 9 && p[i] != 10 && p[i] != 13) { // ASCII control character 0089 return true; 0090 } 0091 } 0092 return false; 0093 } 0094 0095 // the windows-specific code, and the locked directory, are missing from QMimeDatabase. 0096 static KMimeType::Ptr findFromMode(const QString &path /*only used if is_local_file*/, 0097 mode_t mode /*0 if unknown*/, 0098 bool is_local_file) 0099 { 0100 if (is_local_file && (mode == 0 || mode == (mode_t) - 1)) { 0101 KDE_struct_stat buff; 0102 if (KDE::stat(path, &buff) != -1) { 0103 mode = buff.st_mode; 0104 } 0105 } 0106 0107 if (S_ISDIR(mode)) { 0108 // KDE4 TODO: use an overlay instead 0109 #if 0 0110 // Special hack for local files. We want to see whether we 0111 // are allowed to enter the directory 0112 if (is_local_file) { 0113 if (KDE::access(path, R_OK) == -1) { 0114 return KMimeType::mimeType("inode/directory-locked"); 0115 } 0116 } 0117 #endif 0118 return KMimeType::mimeType(QLatin1String("inode/directory")); 0119 } 0120 if (S_ISCHR(mode)) { 0121 return KMimeType::mimeType(QLatin1String("inode/chardevice")); 0122 } 0123 if (S_ISBLK(mode)) { 0124 return KMimeType::mimeType(QLatin1String("inode/blockdevice")); 0125 } 0126 if (S_ISFIFO(mode)) { 0127 return KMimeType::mimeType(QLatin1String("inode/fifo")); 0128 } 0129 if (S_ISSOCK(mode)) { 0130 return KMimeType::mimeType(QLatin1String("inode/socket")); 0131 } 0132 #ifdef Q_OS_WIN 0133 // FIXME: distinguish between mounted & unmounted 0134 int size = path.size(); 0135 if (size == 2 || size == 3) { 0136 //GetDriveTypeW is not defined in wince 0137 #ifndef _WIN32_WCE 0138 unsigned int type = GetDriveTypeW((LPCWSTR) path.utf16()); 0139 switch (type) { 0140 case DRIVE_REMOVABLE: 0141 return KMimeType::mimeType(QLatin1String("media/floppy_mounted")); 0142 case DRIVE_FIXED: 0143 return KMimeType::mimeType(QLatin1String("media/hdd_mounted")); 0144 case DRIVE_REMOTE: 0145 return KMimeType::mimeType(QLatin1String("media/smb_mounted")); 0146 case DRIVE_CDROM: 0147 return KMimeType::mimeType(QLatin1String("media/cdrom_mounted")); 0148 case DRIVE_RAMDISK: 0149 return KMimeType::mimeType(QLatin1String("media/hdd_mounted")); 0150 default: 0151 break; 0152 }; 0153 #else 0154 return KMimeType::mimeType(QLatin1String("media/hdd_mounted")); 0155 #endif 0156 } 0157 #endif 0158 // remote executable file? stop here (otherwise findFromContent can do that better for local files) 0159 if (!is_local_file && S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) { 0160 return KMimeType::mimeType(QLatin1String("application/x-executable")); 0161 } 0162 0163 return KMimeType::Ptr(); 0164 } 0165 0166 /* 0167 Note: in KDE we want the file views to sniff in a delayed manner. 0168 So there's also a fast mode which is: 0169 if no glob matches, or if more than one glob matches, use default mimetype and mark as "can be refined". 0170 */ 0171 0172 KMimeType::Ptr KMimeType::findByUrl(const QUrl &url, mode_t mode, 0173 bool is_local_file, bool fast_mode, 0174 int *accuracy) 0175 { 0176 Q_UNUSED(mode); // special devices only matter locally; caller can use S_ISDIR by itself. 0177 Q_UNUSED(is_local_file); // QUrl can tell us... 0178 QMimeDatabase db; 0179 if (accuracy) { 0180 *accuracy = 80; // not supported anymore; was it really used for anything? 0181 } 0182 if (fast_mode) { 0183 return KMimeType::Ptr(new KMimeType(db.mimeTypeForFile(url.path(), QMimeDatabase::MatchExtension))); 0184 } 0185 return KMimeType::Ptr(new KMimeType(db.mimeTypeForUrl(url))); 0186 } 0187 0188 KMimeType::Ptr KMimeType::findByPath(const QString &path, mode_t mode, 0189 bool fast_mode, int *accuracy) 0190 { 0191 Q_UNUSED(mode); // special devices only matter locally; caller can use S_ISDIR by itself. 0192 QMimeDatabase db; 0193 if (accuracy) { 0194 *accuracy = 80; // not supported anymore; was it really used for anything? 0195 } 0196 if (fast_mode) { 0197 return KMimeType::Ptr(new KMimeType(db.mimeTypeForFile(path, QMimeDatabase::MatchExtension))); 0198 } 0199 return KMimeType::Ptr(new KMimeType(db.mimeTypeForFile(path))); 0200 } 0201 0202 KMimeType::Ptr KMimeType::findByNameAndContent(const QString &name, const QByteArray &data, 0203 mode_t mode, int *accuracy) 0204 { 0205 Q_UNUSED(mode); // If we have data, then this is a regular file anyway... 0206 if (accuracy) { 0207 *accuracy = 80; // not supported anymore; was it really used for anything? 0208 } 0209 QMimeDatabase db; 0210 return KMimeType::Ptr(new KMimeType(db.mimeTypeForFileNameAndData(name, data))); 0211 } 0212 0213 KMimeType::Ptr KMimeType::findByNameAndContent(const QString &name, QIODevice *device, 0214 mode_t mode, int *accuracy) 0215 { 0216 Q_UNUSED(mode); // If we have data, then this is a regular file anyway... 0217 if (accuracy) { 0218 *accuracy = 80; // not supported anymore; was it really used for anything? 0219 } 0220 QMimeDatabase db; 0221 return KMimeType::Ptr(new KMimeType(db.mimeTypeForFileNameAndData(name, device))); 0222 } 0223 0224 QString KMimeType::extractKnownExtension(const QString &fileName) 0225 { 0226 QMimeDatabase db; 0227 return db.suffixForFileName(fileName); 0228 } 0229 0230 KMimeType::Ptr KMimeType::findByContent(const QByteArray &data, int *accuracy) 0231 { 0232 QMimeDatabase db; 0233 if (accuracy) { 0234 *accuracy = 80; // not supported anymore; was it really used for anything? 0235 } 0236 return KMimeType::Ptr(new KMimeType(db.mimeTypeForData(data))); 0237 } 0238 0239 KMimeType::Ptr KMimeType::findByContent(QIODevice *device, int *accuracy) 0240 { 0241 QMimeDatabase db; 0242 if (accuracy) { 0243 *accuracy = 80; // not supported anymore; was it really used for anything? 0244 } 0245 return KMimeType::Ptr(new KMimeType(db.mimeTypeForData(device))); 0246 } 0247 0248 KMimeType::Ptr KMimeType::findByFileContent(const QString &fileName, int *accuracy) 0249 { 0250 QFile device(fileName); 0251 #if 1 0252 // Look at mode first 0253 KMimeType::Ptr mimeFromMode = findFromMode(fileName, 0, true); 0254 if (mimeFromMode) { 0255 if (accuracy) { 0256 *accuracy = 100; 0257 } 0258 return mimeFromMode; 0259 } 0260 #endif 0261 QMimeDatabase db; 0262 KMimeType::Ptr mime(new KMimeType(db.mimeTypeForData(&device))); 0263 if (accuracy) { 0264 *accuracy = mime->isDefault() ? 0 : 80; // not supported anymore; was it really used for anything? 0265 } 0266 return mime; 0267 } 0268 0269 bool KMimeType::isBinaryData(const QString &fileName) 0270 { 0271 QFile file(fileName); 0272 if (!file.open(QIODevice::ReadOnly)) { 0273 return false; // err, whatever 0274 } 0275 const QByteArray data = file.read(32); 0276 return isBufferBinaryData(data); 0277 } 0278 0279 KMimeType::KMimeType(const QMimeType &mime) 0280 : d_ptr(new KMimeTypePrivate(mime)) 0281 { 0282 } 0283 0284 KMimeType::~KMimeType() 0285 { 0286 delete d_ptr; 0287 } 0288 0289 QString KMimeType::favIconForUrl(const QUrl &url) 0290 { 0291 return KIO::favIconForUrl(url); 0292 } 0293 0294 QString KMimeType::iconNameForUrl(const QUrl &url, mode_t mode) 0295 { 0296 Q_UNUSED(mode) 0297 return KIO::iconNameForUrl(url); 0298 } 0299 0300 QString KMimeType::comment() const 0301 { 0302 return d_ptr->m_qmime.comment(); 0303 } 0304 0305 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED 0306 QString KMimeType::parentMimeType() const 0307 { 0308 const QStringList parents = d_ptr->m_qmime.parentMimeTypes(); 0309 if (!parents.isEmpty()) { 0310 return parents.first(); 0311 } 0312 return QString(); 0313 } 0314 #endif 0315 0316 bool KMimeType::is(const QString &mimeTypeName) const 0317 { 0318 return d_ptr->m_qmime.inherits(mimeTypeName); 0319 } 0320 0321 QStringList KMimeType::parentMimeTypes() const 0322 { 0323 return d_ptr->m_qmime.parentMimeTypes(); 0324 } 0325 0326 QStringList KMimeType::allParentMimeTypes() const 0327 { 0328 return d_ptr->m_qmime.allAncestors(); 0329 } 0330 0331 QString KMimeType::defaultMimeType() 0332 { 0333 return QLatin1String("application/octet-stream"); 0334 } 0335 0336 QString KMimeType::iconName() const 0337 { 0338 return d_ptr->m_qmime.iconName(); 0339 } 0340 0341 QStringList KMimeType::patterns() const 0342 { 0343 return d_ptr->m_qmime.globPatterns(); 0344 } 0345 0346 // TODO MOVE TO keditfiletype/mimetypedata.cpp 0347 QString KMimeType::userSpecifiedIconName() const 0348 { 0349 //d->ensureXmlDataLoaded(); 0350 //return d->m_iconName; 0351 return QString(); 0352 } 0353 0354 int KMimeType::sharedMimeInfoVersion() 0355 { 0356 return KMimeTypeRepository::self()->sharedMimeInfoVersion(); 0357 } 0358 0359 QString KMimeType::mainExtension() const 0360 { 0361 #if 1 // HACK START - can be removed once shared-mime-info >= 0.70 is used/required. 0362 // The idea was: first usable pattern from m_lstPatterns. 0363 // But update-mime-database makes a mess of the order of the patterns, 0364 // because it uses a hash internally. 0365 static const struct { 0366 const char *mime; 0367 const char *extension; 0368 } s_hardcodedMimes[] = { 0369 { "text/plain", ".txt" } 0370 }; 0371 if (patterns().count() > 1) { 0372 const QByteArray me = name().toLatin1(); 0373 for (uint i = 0; i < sizeof(s_hardcodedMimes) / sizeof(*s_hardcodedMimes); ++i) { 0374 if (me == s_hardcodedMimes[i].mime) { 0375 return QString::fromLatin1(s_hardcodedMimes[i].extension); 0376 } 0377 } 0378 } 0379 #endif // HACK END 0380 0381 Q_FOREACH (const QString &pattern, patterns()) { 0382 // Skip if if looks like: README or *. or *.* 0383 // or *.JP*G or *.JP? 0384 if (pattern.startsWith(QLatin1String("*.")) && 0385 pattern.length() > 2 && 0386 pattern.indexOf(QLatin1Char('*'), 2) < 0 && pattern.indexOf(QLatin1Char('?'), 2) < 0) { 0387 return pattern.mid(1); 0388 } 0389 } 0390 // TODO we should also look into the parent mimetype's patterns, no? 0391 return QString(); 0392 } 0393 0394 bool KMimeType::matchFileName(const QString &filename, const QString &pattern) 0395 { 0396 return KMimeTypeRepository::matchFileName(filename, pattern); 0397 } 0398 0399 /* 0400 int KMimeTypePrivate::serviceOffersOffset() const 0401 { 0402 return KMimeTypeFactory::self()->serviceOffersOffset(name()); 0403 } 0404 */ 0405 0406 QString KMimeType::name() const 0407 { 0408 return d_ptr->m_qmime.name(); 0409 }