KService

ksycocafactory.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1999 David Faure <faure@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6*/
7
8#include "ksycoca.h"
9#include "ksycocadict_p.h"
10#include "ksycocaentry.h"
11#include "ksycocaentry_p.h"
12#include "ksycocafactory_p.h"
13#include "ksycocatype.h"
14#include "sycocadebug.h"
15
16#include <QDebug>
17#include <QHash>
18#include <QIODevice>
19#include <QThread>
20
21class KSycocaFactoryPrivate
22{
23public:
24 KSycocaFactoryPrivate()
25 {
26 }
27 ~KSycocaFactoryPrivate()
28 {
29 delete m_sycocaDict;
30 }
31
32 int mOffset = 0;
33 int m_sycocaDictOffset = 0;
34 int m_beginEntryOffset = 0;
35 int m_endEntryOffset = 0;
36 KSycocaDict *m_sycocaDict = nullptr;
37};
38
39KSycocaFactory::KSycocaFactory(KSycocaFactoryId factory_id, KSycoca *sycoca)
40 : m_sycoca(sycoca)
41 , d(new KSycocaFactoryPrivate)
42{
43 if (!m_sycoca->isBuilding() && (m_str = m_sycoca->findFactory(factory_id))) {
44 // Read position of index tables....
45 qint32 i;
46 (*m_str) >> i;
47 d->m_sycocaDictOffset = i;
48 (*m_str) >> i;
49 d->m_beginEntryOffset = i;
50 (*m_str) >> i;
51 d->m_endEntryOffset = i;
52
53 QDataStream *str = stream();
54 qint64 saveOffset = str->device()->pos();
55 // Init index tables
56 d->m_sycocaDict = new KSycocaDict(str, d->m_sycocaDictOffset);
57 saveOffset = str->device()->seek(saveOffset);
58 } else {
59 // We are in kbuildsycoca -- build new database!
60 m_entryDict = new KSycocaEntryDict;
61 d->m_sycocaDict = new KSycocaDict;
62 d->m_beginEntryOffset = 0;
63 d->m_endEntryOffset = 0;
64
65 // m_resourceList will be filled in by inherited constructors
66 }
67 m_sycoca->addFactory(this);
68}
69
70KSycocaFactory::~KSycocaFactory()
71{
72 delete m_entryDict;
73}
74
75void KSycocaFactory::saveHeader(QDataStream &str)
76{
77 // Write header
78 str.device()->seek(d->mOffset);
79 str << qint32(d->m_sycocaDictOffset);
80 str << qint32(d->m_beginEntryOffset);
81 str << qint32(d->m_endEntryOffset);
82}
83
84void KSycocaFactory::save(QDataStream &str)
85{
86 if (!m_entryDict) {
87 return; // Error! Function should only be called when building database
88 }
89 if (!d->m_sycocaDict) {
90 return; // Error!
91 }
92
93 d->mOffset = str.device()->pos(); // store position in member variable
94 d->m_sycocaDictOffset = 0;
95
96 // Write header (pass #1)
97 saveHeader(str);
98
99 d->m_beginEntryOffset = str.device()->pos();
100
101 // Write all entries.
102 int entryCount = 0;
103 for (KSycocaEntry::Ptr entry : std::as_const(*m_entryDict)) {
104 entry->d_ptr->save(str);
105 entryCount++;
106 }
107
108 d->m_endEntryOffset = str.device()->pos();
109
110 // Write indices...
111 // Linear index
112 str << qint32(entryCount);
113 for (const KSycocaEntry::Ptr &entry : std::as_const(*m_entryDict)) {
114 str << qint32(entry.data()->offset());
115 }
116
117 // Dictionary index
118 d->m_sycocaDictOffset = str.device()->pos();
119 d->m_sycocaDict->save(str);
120
121 qint64 endOfFactoryData = str.device()->pos();
122
123 // Update header (pass #2)
124 saveHeader(str);
125
126 // Seek to end.
127 str.device()->seek(endOfFactoryData);
128}
129
130void KSycocaFactory::addEntry(const KSycocaEntry::Ptr &newEntry)
131{
132 if (!m_entryDict) {
133 return; // Error! Function should only be called when
134 }
135 // building database
136
137 if (!d->m_sycocaDict) {
138 return; // Error!
139 }
140
141 KSycocaEntry::Ptr oldEntry = m_entryDict->value(newEntry->storageId());
142 if (oldEntry) {
143 // Already exists -> replace
144 // We found a more-local override, e.g. ~/.local/share/applications/kde5/foo.desktop
145 // So forget about the more global file.
146 //
147 // This can also happen with two .protocol files using the same protocol= entry.
148 // If we didn't remove one here, we would end up asserting because save()
149 // wasn't called on one of the entries.
150 // qDebug() << "removing" << oldEntry.data() << oldEntry->entryPath() << "because of" << newEntry->entryPath() << "they have the same storageId" <<
151 // newEntry->storageId();
152 removeEntry(newEntry->storageId());
153 }
154
155 const QString name = newEntry->storageId();
156 m_entryDict->insert(name, newEntry);
157 d->m_sycocaDict->add(name, newEntry);
158}
159
160void KSycocaFactory::removeEntry(const QString &entryName)
161{
162 if (!m_entryDict) {
163 return; // Error! Function should only be called when
164 }
165 // building database
166
167 if (!d->m_sycocaDict) {
168 return; // Error!
169 }
170
171 m_entryDict->remove(entryName);
172 d->m_sycocaDict->remove(entryName); // O(N)
173}
174
175KSycocaEntry::List KSycocaFactory::allEntries() const
176{
178
179 // Assume we're NOT building a database
180
181 QDataStream *str = stream();
182 if (!str) {
183 return list;
184 }
185 str->device()->seek(d->m_endEntryOffset);
186 qint32 entryCount;
187 (*str) >> entryCount;
188
189 if (entryCount > 8192) {
190 qCWarning(SYCOCA) << QThread::currentThread() << "error detected in factory" << this;
192 return list;
193 }
194
195 // offsetList is needed because createEntry() modifies the stream position
196 qint32 *offsetList = new qint32[entryCount];
197 for (int i = 0; i < entryCount; i++) {
198 (*str) >> offsetList[i];
199 }
200
201 for (int i = 0; i < entryCount; i++) {
202 KSycocaEntry *newEntry = createEntry(offsetList[i]);
203 if (newEntry) {
204 list.append(KSycocaEntry::Ptr(newEntry));
205 }
206 }
207 delete[] offsetList;
208 return list;
209}
210
211int KSycocaFactory::offset() const
212{
213 return d->mOffset;
214}
215
216const KSycocaResourceList &KSycocaFactory::resourceList() const
217{
218 return m_resourceList;
219}
220
221const KSycocaDict *KSycocaFactory::sycocaDict() const
222{
223 return d->m_sycocaDict;
224}
225
226bool KSycocaFactory::isEmpty() const
227{
228 return d->m_beginEntryOffset == d->m_endEntryOffset;
229}
230
231QDataStream *KSycocaFactory::stream() const
232{
233 return m_str;
234}
235
236QStringList KSycocaFactory::allDirectories(const QString &subdir)
237{
238 // We don't use QStandardPaths::locateAll() because we want all paths, even those that don't exist yet
240 for (auto &dir : topDirs) {
241 dir += QLatin1Char('/') + subdir;
242 }
243 return topDirs;
244}
245
246void KSycocaFactory::virtual_hook(int /*id*/, void * /*data*/)
247{
248 /*BASE::virtual_hook( id, data );*/
249}
Base class for all Sycoca entries.
static void flagError()
A read error occurs.
Definition ksycoca.cpp:711
KSycocaFactoryId
A KSycocaFactoryId is a code (out of the KSycocaFactoryId enum) assigned to each class type derived f...
Definition ksycocatype.h:39
KIOCORE_EXPORT QString dir(const QString &fileClass)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QString name(StandardAction id)
QIODevice * device() const const
virtual qint64 pos() const const
virtual bool seek(qint64 pos)
void append(QList< T > &&value)
QStringList standardLocations(StandardLocation type)
QThread * currentThread()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:13:19 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.