Warning, file /frameworks/kservice/src/sycoca/ksycocafactory.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 1999 David Faure <faure@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "ksycoca.h" 0009 #include "ksycocadict_p.h" 0010 #include "ksycocaentry.h" 0011 #include "ksycocaentry_p.h" 0012 #include "ksycocafactory_p.h" 0013 #include "ksycocatype.h" 0014 #include "sycocadebug.h" 0015 0016 #include <QDebug> 0017 #include <QHash> 0018 #include <QIODevice> 0019 #include <QThread> 0020 0021 class KSycocaFactoryPrivate 0022 { 0023 public: 0024 KSycocaFactoryPrivate() 0025 { 0026 } 0027 ~KSycocaFactoryPrivate() 0028 { 0029 delete m_sycocaDict; 0030 } 0031 0032 int mOffset = 0; 0033 int m_sycocaDictOffset = 0; 0034 int m_beginEntryOffset = 0; 0035 int m_endEntryOffset = 0; 0036 KSycocaDict *m_sycocaDict = nullptr; 0037 }; 0038 0039 KSycocaFactory::KSycocaFactory(KSycocaFactoryId factory_id, KSycoca *sycoca) 0040 : m_sycoca(sycoca) 0041 , d(new KSycocaFactoryPrivate) 0042 { 0043 if (!m_sycoca->isBuilding() && (m_str = m_sycoca->findFactory(factory_id))) { 0044 // Read position of index tables.... 0045 qint32 i; 0046 (*m_str) >> i; 0047 d->m_sycocaDictOffset = i; 0048 (*m_str) >> i; 0049 d->m_beginEntryOffset = i; 0050 (*m_str) >> i; 0051 d->m_endEntryOffset = i; 0052 0053 QDataStream *str = stream(); 0054 qint64 saveOffset = str->device()->pos(); 0055 // Init index tables 0056 d->m_sycocaDict = new KSycocaDict(str, d->m_sycocaDictOffset); 0057 saveOffset = str->device()->seek(saveOffset); 0058 } else { 0059 // We are in kbuildsycoca -- build new database! 0060 m_entryDict = new KSycocaEntryDict; 0061 d->m_sycocaDict = new KSycocaDict; 0062 d->m_beginEntryOffset = 0; 0063 d->m_endEntryOffset = 0; 0064 0065 // m_resourceList will be filled in by inherited constructors 0066 } 0067 m_sycoca->addFactory(this); 0068 } 0069 0070 KSycocaFactory::~KSycocaFactory() 0071 { 0072 delete m_entryDict; 0073 } 0074 0075 void KSycocaFactory::saveHeader(QDataStream &str) 0076 { 0077 // Write header 0078 str.device()->seek(d->mOffset); 0079 str << qint32(d->m_sycocaDictOffset); 0080 str << qint32(d->m_beginEntryOffset); 0081 str << qint32(d->m_endEntryOffset); 0082 } 0083 0084 void KSycocaFactory::save(QDataStream &str) 0085 { 0086 if (!m_entryDict) { 0087 return; // Error! Function should only be called when building database 0088 } 0089 if (!d->m_sycocaDict) { 0090 return; // Error! 0091 } 0092 0093 d->mOffset = str.device()->pos(); // store position in member variable 0094 d->m_sycocaDictOffset = 0; 0095 0096 // Write header (pass #1) 0097 saveHeader(str); 0098 0099 d->m_beginEntryOffset = str.device()->pos(); 0100 0101 // Write all entries. 0102 int entryCount = 0; 0103 for (KSycocaEntry::Ptr entry : std::as_const(*m_entryDict)) { 0104 entry->d_ptr->save(str); 0105 entryCount++; 0106 } 0107 0108 d->m_endEntryOffset = str.device()->pos(); 0109 0110 // Write indices... 0111 // Linear index 0112 str << qint32(entryCount); 0113 for (const KSycocaEntry::Ptr &entry : std::as_const(*m_entryDict)) { 0114 str << qint32(entry.data()->offset()); 0115 } 0116 0117 // Dictionary index 0118 d->m_sycocaDictOffset = str.device()->pos(); 0119 d->m_sycocaDict->save(str); 0120 0121 qint64 endOfFactoryData = str.device()->pos(); 0122 0123 // Update header (pass #2) 0124 saveHeader(str); 0125 0126 // Seek to end. 0127 str.device()->seek(endOfFactoryData); 0128 } 0129 0130 void KSycocaFactory::addEntry(const KSycocaEntry::Ptr &newEntry) 0131 { 0132 if (!m_entryDict) { 0133 return; // Error! Function should only be called when 0134 } 0135 // building database 0136 0137 if (!d->m_sycocaDict) { 0138 return; // Error! 0139 } 0140 0141 KSycocaEntry::Ptr oldEntry = m_entryDict->value(newEntry->storageId()); 0142 if (oldEntry) { 0143 // Already exists -> replace 0144 // We found a more-local override, e.g. ~/.local/share/applications/kde5/foo.desktop 0145 // So forget about the more global file. 0146 // 0147 // This can also happen with two .protocol files using the same protocol= entry. 0148 // If we didn't remove one here, we would end up asserting because save() 0149 // wasn't called on one of the entries. 0150 // qDebug() << "removing" << oldEntry.data() << oldEntry->entryPath() << "because of" << newEntry->entryPath() << "they have the same storageId" << 0151 // newEntry->storageId(); 0152 removeEntry(newEntry->storageId()); 0153 } 0154 0155 const QString name = newEntry->storageId(); 0156 m_entryDict->insert(name, newEntry); 0157 d->m_sycocaDict->add(name, newEntry); 0158 } 0159 0160 void KSycocaFactory::removeEntry(const QString &entryName) 0161 { 0162 if (!m_entryDict) { 0163 return; // Error! Function should only be called when 0164 } 0165 // building database 0166 0167 if (!d->m_sycocaDict) { 0168 return; // Error! 0169 } 0170 0171 m_entryDict->remove(entryName); 0172 d->m_sycocaDict->remove(entryName); // O(N) 0173 } 0174 0175 KSycocaEntry::List KSycocaFactory::allEntries() const 0176 { 0177 KSycocaEntry::List list; 0178 0179 // Assume we're NOT building a database 0180 0181 QDataStream *str = stream(); 0182 if (!str) { 0183 return list; 0184 } 0185 str->device()->seek(d->m_endEntryOffset); 0186 qint32 entryCount; 0187 (*str) >> entryCount; 0188 0189 if (entryCount > 8192) { 0190 qCWarning(SYCOCA) << QThread::currentThread() << "error detected in factory" << this; 0191 KSycoca::flagError(); 0192 return list; 0193 } 0194 0195 // offsetList is needed because createEntry() modifies the stream position 0196 qint32 *offsetList = new qint32[entryCount]; 0197 for (int i = 0; i < entryCount; i++) { 0198 (*str) >> offsetList[i]; 0199 } 0200 0201 for (int i = 0; i < entryCount; i++) { 0202 KSycocaEntry *newEntry = createEntry(offsetList[i]); 0203 if (newEntry) { 0204 list.append(KSycocaEntry::Ptr(newEntry)); 0205 } 0206 } 0207 delete[] offsetList; 0208 return list; 0209 } 0210 0211 int KSycocaFactory::offset() const 0212 { 0213 return d->mOffset; 0214 } 0215 0216 const KSycocaResourceList &KSycocaFactory::resourceList() const 0217 { 0218 return m_resourceList; 0219 } 0220 0221 const KSycocaDict *KSycocaFactory::sycocaDict() const 0222 { 0223 return d->m_sycocaDict; 0224 } 0225 0226 bool KSycocaFactory::isEmpty() const 0227 { 0228 return d->m_beginEntryOffset == d->m_endEntryOffset; 0229 } 0230 0231 QDataStream *KSycocaFactory::stream() const 0232 { 0233 return m_str; 0234 } 0235 0236 QStringList KSycocaFactory::allDirectories(const QString &subdir) 0237 { 0238 // We don't use QStandardPaths::locateAll() because we want all paths, even those that don't exist yet 0239 QStringList topDirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); 0240 for (auto &dir : topDirs) { 0241 dir += QLatin1Char('/') + subdir; 0242 } 0243 return topDirs; 0244 } 0245 0246 void KSycocaFactory::virtual_hook(int /*id*/, void * /*data*/) 0247 { 0248 /*BASE::virtual_hook( id, data );*/ 0249 }