File indexing completed on 2024-11-03 12:41:43
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 1999-2006 David Faure <faure@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include "kservice.h" 0009 #include "kservicefactory_p.h" 0010 #include "ksycoca.h" 0011 #include "ksycocadict_p.h" 0012 #include "ksycocatype.h" 0013 #include "servicesdebug.h" 0014 #include <QDir> 0015 #include <QFile> 0016 0017 extern int servicesDebugArea(); 0018 0019 KServiceFactory::KServiceFactory(KSycoca *db) 0020 : KSycocaFactory(KST_KServiceFactory, db) 0021 , m_nameDict(nullptr) 0022 , m_relNameDict(nullptr) 0023 , m_menuIdDict(nullptr) 0024 { 0025 m_offerListOffset = 0; 0026 m_nameDictOffset = 0; 0027 m_relNameDictOffset = 0; 0028 m_menuIdDictOffset = 0; 0029 if (!sycoca()->isBuilding()) { 0030 QDataStream *str = stream(); 0031 Q_ASSERT(str); 0032 if (!str) { 0033 return; 0034 } 0035 // Read Header 0036 qint32 i; 0037 (*str) >> i; 0038 m_nameDictOffset = i; 0039 (*str) >> i; 0040 m_relNameDictOffset = i; 0041 (*str) >> i; 0042 m_offerListOffset = i; 0043 (*str) >> i; 0044 m_menuIdDictOffset = i; 0045 0046 const qint64 saveOffset = str->device()->pos(); 0047 // Init index tables 0048 m_nameDict = new KSycocaDict(str, m_nameDictOffset); 0049 // Init index tables 0050 m_relNameDict = new KSycocaDict(str, m_relNameDictOffset); 0051 // Init index tables 0052 m_menuIdDict = new KSycocaDict(str, m_menuIdDictOffset); 0053 str->device()->seek(saveOffset); 0054 } 0055 } 0056 0057 KServiceFactory::~KServiceFactory() 0058 { 0059 delete m_nameDict; 0060 delete m_relNameDict; 0061 delete m_menuIdDict; 0062 } 0063 0064 KService::Ptr KServiceFactory::findServiceByName(const QString &_name) 0065 { 0066 if (!sycocaDict()) { 0067 return KService::Ptr(); // Error! 0068 } 0069 0070 // Warning : this assumes we're NOT building a database 0071 // But since findServiceByName isn't called in that case... 0072 // [ see KServiceTypeFactory for how to do it if needed ] 0073 0074 int offset = sycocaDict()->find_string(_name); 0075 if (!offset) { 0076 return KService::Ptr(); // Not found 0077 } 0078 0079 KService::Ptr newService(createEntry(offset)); 0080 0081 // Check whether the dictionary was right. 0082 if (newService && (newService->name() != _name)) { 0083 // No it wasn't... 0084 return KService::Ptr(); 0085 } 0086 return newService; 0087 } 0088 0089 KService::Ptr KServiceFactory::findServiceByDesktopName(const QString &_name) 0090 { 0091 if (!m_nameDict) { 0092 return KService::Ptr(); // Error! 0093 } 0094 0095 // Warning : this assumes we're NOT building a database 0096 // KBuildServiceFactory reimplements it for the case where we are building one 0097 0098 int offset = m_nameDict->find_string(_name); 0099 if (!offset) { 0100 return KService::Ptr(); // Not found 0101 } 0102 0103 KService::Ptr newService(createEntry(offset)); 0104 0105 // Check whether the dictionary was right. 0106 if (newService && (newService->desktopEntryName() != _name)) { 0107 // No it wasn't... 0108 return KService::Ptr(); 0109 } 0110 return newService; 0111 } 0112 0113 KService::Ptr KServiceFactory::findServiceByDesktopPath(const QString &_name) 0114 { 0115 if (!m_relNameDict) { 0116 return KService::Ptr(); // Error! 0117 } 0118 0119 // Warning : this assumes we're NOT building a database 0120 // KBuildServiceFactory reimplements it for the case where we are building one 0121 0122 int offset = m_relNameDict->find_string(_name); 0123 if (!offset) { 0124 // qCDebug(SERVICES) << "findServiceByDesktopPath:" << _name << "not found"; 0125 return KService::Ptr(); // Not found 0126 } 0127 0128 KService::Ptr newService(createEntry(offset)); 0129 if (!newService) { 0130 qCDebug(SERVICES) << "createEntry failed!"; 0131 } 0132 // Check whether the dictionary was right 0133 // It's ok that it's wrong, for the case where we're looking up an unknown service, 0134 // and the hash value gave us another one. 0135 if (newService && (newService->entryPath() != _name)) { 0136 // No it wasn't... 0137 return KService::Ptr(); 0138 } 0139 return newService; 0140 } 0141 0142 KService::Ptr KServiceFactory::findServiceByMenuId(const QString &_menuId) 0143 { 0144 if (!m_menuIdDict) { 0145 return KService::Ptr(); // Error! 0146 } 0147 0148 // Warning : this assumes we're NOT building a database 0149 // KBuildServiceFactory reimplements it for the case where we are building one 0150 0151 int offset = m_menuIdDict->find_string(_menuId); 0152 if (!offset) { 0153 return KService::Ptr(); // Not found 0154 } 0155 0156 KService::Ptr newService(createEntry(offset)); 0157 0158 // Check whether the dictionary was right. 0159 if (newService && (newService->menuId() != _menuId)) { 0160 // No it wasn't... 0161 return KService::Ptr(); 0162 } 0163 return newService; 0164 } 0165 0166 KService::Ptr KServiceFactory::findServiceByStorageId(const QString &_storageId) 0167 { 0168 KService::Ptr service = findServiceByMenuId(_storageId); 0169 if (service) { 0170 return service; 0171 } 0172 0173 service = findServiceByDesktopPath(_storageId); 0174 if (service) { 0175 return service; 0176 } 0177 0178 if (!QDir::isRelativePath(_storageId) && QFile::exists(_storageId)) { 0179 return KService::Ptr(new KService(_storageId)); 0180 } 0181 0182 QString tmp = _storageId; 0183 tmp = tmp.mid(tmp.lastIndexOf(QLatin1Char('/')) + 1); // Strip dir 0184 0185 if (tmp.endsWith(QLatin1String(".desktop"))) { 0186 tmp.chop(8); 0187 } 0188 0189 if (tmp.endsWith(QLatin1String(".kdelnk"))) { 0190 tmp.chop(7); 0191 } 0192 0193 service = findServiceByDesktopName(tmp); 0194 0195 return service; 0196 } 0197 0198 KService *KServiceFactory::createEntry(int offset) const 0199 { 0200 KSycocaType type; 0201 QDataStream *str = sycoca()->findEntry(offset, type); 0202 if (type != KST_KService) { 0203 qCWarning(SERVICES) << "KServiceFactory: unexpected object entry in KSycoca database (type=" << int(type) << ")"; 0204 return nullptr; 0205 } 0206 KService *newEntry = new KService(*str, offset); 0207 if (!newEntry->isValid()) { 0208 qCWarning(SERVICES) << "KServiceFactory: corrupt object in KSycoca database!"; 0209 delete newEntry; 0210 newEntry = nullptr; 0211 } 0212 return newEntry; 0213 } 0214 0215 KService::List KServiceFactory::allServices() 0216 { 0217 KService::List result; 0218 const KSycocaEntry::List list = allEntries(); 0219 for (const auto &entryPtr : list) { 0220 if (entryPtr->isType(KST_KService)) { 0221 result.append(KService::Ptr(static_cast<KService *>(entryPtr.data()))); 0222 } 0223 } 0224 return result; 0225 } 0226 0227 QStringList KServiceFactory::resourceDirs() 0228 { 0229 return KSycocaFactory::allDirectories(QStringLiteral("kservices5")) + KSycocaFactory::allDirectories(QStringLiteral("applications")); 0230 } 0231 0232 QList<KServiceOffer> KServiceFactory::offers(int serviceTypeOffset, int serviceOffersOffset) 0233 { 0234 QList<KServiceOffer> list; 0235 0236 // Jump to the offer list 0237 QDataStream *str = stream(); 0238 str->device()->seek(m_offerListOffset + serviceOffersOffset); 0239 0240 qint32 aServiceTypeOffset; 0241 qint32 aServiceOffset; 0242 qint32 initialPreference; 0243 qint32 mimeTypeInheritanceLevel; 0244 while (true) { 0245 (*str) >> aServiceTypeOffset; 0246 if (aServiceTypeOffset) { 0247 (*str) >> aServiceOffset; 0248 (*str) >> initialPreference; 0249 (*str) >> mimeTypeInheritanceLevel; 0250 if (aServiceTypeOffset == serviceTypeOffset) { 0251 // Save stream position ! 0252 const qint64 savedPos = str->device()->pos(); 0253 // Create Service 0254 KService *serv = createEntry(aServiceOffset); 0255 if (serv) { 0256 KService::Ptr servPtr(serv); 0257 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 69) 0258 list.append(KServiceOffer(servPtr, initialPreference, mimeTypeInheritanceLevel, servPtr->allowAsDefault())); 0259 #else 0260 list.append(KServiceOffer(servPtr, initialPreference, mimeTypeInheritanceLevel)); 0261 #endif 0262 } 0263 // Restore position 0264 str->device()->seek(savedPos); 0265 } else { 0266 break; // too far 0267 } 0268 } else { 0269 break; // 0 => end of list 0270 } 0271 } 0272 return list; 0273 } 0274 0275 KService::List KServiceFactory::serviceOffers(const KServiceType::Ptr &serviceType) 0276 { 0277 return serviceOffers(serviceType->offset(), serviceType->serviceOffersOffset()); 0278 } 0279 0280 KService::List KServiceFactory::serviceOffers(int serviceTypeOffset, int serviceOffersOffset) 0281 { 0282 KService::List list; 0283 0284 // Jump to the offer list 0285 QDataStream *str = stream(); 0286 str->device()->seek(m_offerListOffset + serviceOffersOffset); 0287 0288 qint32 aServiceTypeOffset; 0289 qint32 aServiceOffset; 0290 qint32 initialPreference; 0291 qint32 mimeTypeInheritanceLevel; 0292 while (true) { 0293 (*str) >> aServiceTypeOffset; 0294 if (aServiceTypeOffset) { 0295 (*str) >> aServiceOffset; 0296 (*str) >> initialPreference; // unused (remove once KMimeTypeTrader/KServiceTypeTrader are gone) 0297 (*str) >> mimeTypeInheritanceLevel; // unused (remove once KMimeTypeTrader/KServiceTypeTrader are gone) 0298 if (aServiceTypeOffset == serviceTypeOffset) { 0299 // Save stream position ! 0300 const qint64 savedPos = str->device()->pos(); 0301 // Create service 0302 KService *serv = createEntry(aServiceOffset); 0303 if (serv) { 0304 list.append(KService::Ptr(serv)); 0305 } 0306 // Restore position 0307 str->device()->seek(savedPos); 0308 } else { 0309 break; // too far 0310 } 0311 } else { 0312 break; // 0 => end of list 0313 } 0314 } 0315 return list; 0316 } 0317 0318 bool KServiceFactory::hasOffer(const KServiceType::Ptr &serviceType, const KService::Ptr &testedService) 0319 { 0320 return hasOffer(serviceType->offset(), serviceType->serviceOffersOffset(), testedService->offset()); 0321 } 0322 0323 bool KServiceFactory::hasOffer(int serviceTypeOffset, int serviceOffersOffset, int testedServiceOffset) 0324 { 0325 // Save stream position 0326 QDataStream *str = stream(); 0327 const qint64 savedPos = str->device()->pos(); 0328 0329 // Jump to the offer list 0330 str->device()->seek(m_offerListOffset + serviceOffersOffset); 0331 bool found = false; 0332 qint32 aServiceTypeOffset; 0333 qint32 aServiceOffset; 0334 qint32 initialPreference; 0335 qint32 mimeTypeInheritanceLevel; 0336 while (!found) { 0337 (*str) >> aServiceTypeOffset; 0338 if (aServiceTypeOffset) { 0339 (*str) >> aServiceOffset; 0340 (*str) >> initialPreference; 0341 (*str) >> mimeTypeInheritanceLevel; 0342 if (aServiceTypeOffset == serviceTypeOffset) { 0343 if (aServiceOffset == testedServiceOffset) { 0344 found = true; 0345 } 0346 } else { 0347 break; // too far 0348 } 0349 } else { 0350 break; // 0 => end of list 0351 } 0352 } 0353 // Restore position 0354 str->device()->seek(savedPos); 0355 return found; 0356 } 0357 0358 void KServiceFactory::virtual_hook(int id, void *data) 0359 { 0360 KSycocaFactory::virtual_hook(id, data); 0361 }