File indexing completed on 2024-04-28 05:27:04
0001 /* This file is part of the KDE project 0002 SPDX-FileCopyrightText: 2007, 2008 David Faure <faure@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "mimetypewriter.h" 0008 0009 #include <QDebug> 0010 #include <QDir> 0011 #include <QFile> 0012 #include <QStandardPaths> 0013 #include <QXmlStreamWriter> 0014 0015 #include <KProcess> 0016 0017 class MimeTypeWriterPrivate 0018 { 0019 public: 0020 QString localFilePath() const; 0021 0022 QString m_mimeType; 0023 QString m_comment; 0024 QString m_iconName; 0025 QStringList m_patterns; 0026 QString m_marker; 0027 }; 0028 0029 MimeTypeWriter::MimeTypeWriter(const QString &mimeType) 0030 : d(new MimeTypeWriterPrivate) 0031 { 0032 d->m_mimeType = mimeType; 0033 Q_ASSERT(!mimeType.isEmpty()); 0034 } 0035 0036 MimeTypeWriter::~MimeTypeWriter() 0037 { 0038 delete d; 0039 } 0040 0041 void MimeTypeWriter::setComment(const QString &comment) 0042 { 0043 d->m_comment = comment; 0044 } 0045 0046 void MimeTypeWriter::setPatterns(const QStringList &patterns) 0047 { 0048 d->m_patterns = patterns; 0049 } 0050 0051 void MimeTypeWriter::setIconName(const QString &iconName) 0052 { 0053 d->m_iconName = iconName; 0054 } 0055 0056 void MimeTypeWriter::setMarker(const QString &marker) 0057 { 0058 d->m_marker = marker; 0059 } 0060 0061 bool MimeTypeWriter::write() 0062 { 0063 const QString packageFileName = d->localFilePath(); 0064 qDebug() << "writing" << packageFileName; 0065 QFile packageFile(packageFileName); 0066 if (!packageFile.open(QIODevice::WriteOnly)) { 0067 qCritical() << "Couldn't open" << packageFileName << "for writing"; 0068 return false; 0069 } 0070 QXmlStreamWriter writer(&packageFile); 0071 writer.setAutoFormatting(true); 0072 writer.writeStartDocument(); 0073 if (!d->m_marker.isEmpty()) { 0074 writer.writeComment(d->m_marker); 0075 } 0076 const QString nsUri = QStringLiteral("http://www.freedesktop.org/standards/shared-mime-info"); 0077 writer.writeDefaultNamespace(nsUri); 0078 writer.writeStartElement(QStringLiteral("mime-info")); 0079 writer.writeStartElement(nsUri, QStringLiteral("mime-type")); 0080 writer.writeAttribute(QStringLiteral("type"), d->m_mimeType); 0081 0082 if (!d->m_comment.isEmpty()) { 0083 writer.writeStartElement(nsUri, QStringLiteral("comment")); 0084 writer.writeCharacters(d->m_comment); 0085 writer.writeEndElement(); // comment 0086 } 0087 0088 if (!d->m_iconName.isEmpty()) { 0089 // User-specified icon name 0090 writer.writeStartElement(nsUri, QStringLiteral("icon")); 0091 writer.writeAttribute(QStringLiteral("name"), d->m_iconName); 0092 writer.writeEndElement(); // icon 0093 } 0094 0095 // Allow this local definition to override the global definition 0096 writer.writeStartElement(nsUri, QStringLiteral("glob-deleteall")); 0097 writer.writeEndElement(); // glob-deleteall 0098 0099 for (const QString &pattern : std::as_const(d->m_patterns)) { 0100 writer.writeStartElement(nsUri, QStringLiteral("glob")); 0101 writer.writeAttribute(QStringLiteral("pattern"), pattern); 0102 writer.writeEndElement(); // glob 0103 } 0104 0105 writer.writeEndElement(); // mime-info 0106 writer.writeEndElement(); // mime-type 0107 writer.writeEndDocument(); 0108 return true; 0109 } 0110 0111 void MimeTypeWriter::runUpdateMimeDatabase() 0112 { 0113 const QString localPackageDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/mime/"); 0114 Q_ASSERT(!localPackageDir.isEmpty()); 0115 KProcess proc; 0116 proc << QStringLiteral("update-mime-database"); 0117 proc << localPackageDir; 0118 const int exitCode = proc.execute(); 0119 if (exitCode) { 0120 qWarning() << proc.program() << "exited with error code" << exitCode; 0121 } 0122 } 0123 0124 QString MimeTypeWriterPrivate::localFilePath() const 0125 { 0126 // XDG shared mime: we must write into a <kdehome>/share/mime/packages/ file... 0127 // To simplify our job, let's use one "input" file per mimetype, in the user's dir. 0128 // (this writes into $HOME/.local/share/mime by default) 0129 // 0130 // We could also use Override.xml, says the spec, but then we'd need to merge with other mimetypes, 0131 // and in ~/.local we don't really expect other packages to be installed anyway... 0132 QString baseName = m_mimeType; 0133 baseName.replace(QLatin1Char('/'), QLatin1Char('-')); 0134 QString packagesDirName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/mime/") + QStringLiteral("packages/"); 0135 // create the directory, the saving will fail if it doesn't exist (bug#356237) 0136 QDir(packagesDirName).mkpath(QStringLiteral(".")); 0137 return packagesDirName + baseName + QStringLiteral(".xml"); 0138 } 0139 0140 static QString existingDefinitionFile(const QString &mimeType) 0141 { 0142 QString baseName = mimeType; 0143 baseName.replace(QLatin1Char('/'), QLatin1Char('-')); 0144 return QStandardPaths::locate(QStandardPaths::GenericDataLocation, 0145 QLatin1String("mime/") + QStringLiteral("packages/") + baseName + QStringLiteral(".xml")); 0146 } 0147 0148 bool MimeTypeWriter::hasDefinitionFile(const QString &mimeType) 0149 { 0150 return !existingDefinitionFile(mimeType).isEmpty(); 0151 } 0152 0153 void MimeTypeWriter::removeOwnMimeType(const QString &mimeType) 0154 { 0155 const QString file = existingDefinitionFile(mimeType); 0156 Q_ASSERT(!file.isEmpty()); 0157 QFile::remove(file); 0158 // We must also remove the generated XML file, update-mime-database doesn't do that, for unknown media types 0159 QString xmlFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("mime/") + mimeType + QStringLiteral(".xml")); 0160 QFile::remove(xmlFile); 0161 } 0162 0163 /// WARNING: this code is duplicated between apps/nsplugins and runtime/filetypes