1 | /* |
2 | SPDX-FileCopyrightText: 2007-2011 Aaron Seigo <aseigo@kde.org> |
3 | |
4 | SPDX-License-Identifier: LGPL-2.0-or-later |
5 | */ |
6 | |
7 | #ifndef KPACKAGE_PACKAGE_H |
8 | #define KPACKAGE_PACKAGE_H |
9 | |
10 | #include <QCryptographicHash> |
11 | #include <QMetaType> |
12 | #include <QStringList> |
13 | #include <QUrl> |
14 | |
15 | #include <KPluginMetaData> |
16 | |
17 | #include <kpackage/package_export.h> |
18 | |
19 | #include <KJob> |
20 | |
21 | namespace KPackage |
22 | { |
23 | /** |
24 | * @class Package kpackage/package.h <KPackage/Package> |
25 | * |
26 | * @short object representing an installed package |
27 | * |
28 | * Package defines what is in a package and provides easy access to the contents. |
29 | * |
30 | * To define a package, one might write the following code: |
31 | * |
32 | @code |
33 | Package package; |
34 | |
35 | package.addDirectoryDefinition("images", "pics/"); |
36 | package.setMimeTypes("images", QStringList{"image/svg", "image/png", "image/jpeg"}); |
37 | |
38 | package.addDirectoryDefinition("scripts", "code/"); |
39 | package.setMimeTypes("scripts", QStringList{"text/\*"}); |
40 | |
41 | package.addFileDefinition("mainscript", "code/main.js"); |
42 | package.setRequired("mainscript", true); |
43 | @endcode |
44 | * One may also choose to create a subclass of PackageStructure and include the setup |
45 | * in the constructor. |
46 | * |
47 | * Either way, Package creates a self-documenting contract between the packager and |
48 | * the application without exposing package internals such as actual on-disk structure |
49 | * of the package or requiring that all contents be explicitly known ahead of time. |
50 | * |
51 | * Subclassing PackageStructure does have provide a number of potential const benefits: |
52 | * * the package can be notified of path changes via the virtual pathChanged() method |
53 | * * the subclass may implement mechanisms to install and remove packages using the |
54 | * virtual install and uninstall methods |
55 | * * subclasses can be compiled as plugins for easy re-use |
56 | **/ |
57 | // TODO: write documentation on USING a package |
58 | |
59 | class PackagePrivate; |
60 | class PackageStructure; |
61 | |
62 | class KPACKAGE_EXPORT Package |
63 | { |
64 | public: |
65 | /** |
66 | * Default constructor |
67 | * |
68 | * @param structure if a null pointer is passed in, this will creates an empty (invalid) Package; |
69 | * otherwise the structure is allowed to set up the Package's initial layout |
70 | */ |
71 | explicit Package(PackageStructure *structure = nullptr); |
72 | |
73 | /** |
74 | * Copy constructor |
75 | */ |
76 | Package(const Package &other); |
77 | |
78 | virtual ~Package(); |
79 | |
80 | /** |
81 | * Assignment operator |
82 | */ |
83 | Package &operator=(const Package &rhs); |
84 | |
85 | /** |
86 | * @return true if this package has a valid PackageStructure associatedw it with it. |
87 | * A package may not be valid, but have a valid structure. Useful when dealing with |
88 | * Package objects in a semi-initialized state (e.g. before calling setPath()) |
89 | * @since 5.1 |
90 | */ |
91 | bool hasValidStructure() const; |
92 | |
93 | /** |
94 | * @return true if all the required components exist |
95 | **/ |
96 | bool isValid() const; |
97 | |
98 | /** |
99 | * Sets the path to the root of this package |
100 | * @param path an absolute path, or a relative path to the default package root |
101 | */ |
102 | void setPath(const QString &path); |
103 | |
104 | /** |
105 | * @return the path to the root of this particular package |
106 | */ |
107 | const QString path() const; |
108 | |
109 | /** |
110 | * Get the path to a given file based on the key and an optional filename. |
111 | * Example: finding the main script in a scripting package: |
112 | * filePath("mainscript") |
113 | * |
114 | * Example: finding a specific image in the images directory: |
115 | * filePath("images", "myimage.png") |
116 | * |
117 | * @param key the key of the file type to look for, |
118 | * @param filename optional name of the file to locate within the package |
119 | * @return path to the file on disk. QString() if not found. |
120 | **/ |
121 | QString filePath(const QByteArray &key, const QString &filename = QString()) const; |
122 | |
123 | /** |
124 | * Get the url to a given file based on the key and an optional filename, is the file:// or qrc:// format |
125 | * Example: finding the main script in a scripting package: |
126 | * filePath("mainscript") |
127 | * |
128 | * Example: finding a specific image in the images directory: |
129 | * filePath("images", "myimage.png") |
130 | * |
131 | * @param key the key of the file type to look for, |
132 | * @param filename optional name of the file to locate within the package |
133 | * @return path to the file on disk. QUrl() if not found. |
134 | * @since 5.41 |
135 | **/ |
136 | QUrl fileUrl(const QByteArray &key, const QString &filename = QString()) const; |
137 | |
138 | /** |
139 | * Get the list of files of a given type. |
140 | * |
141 | * @param fileType the type of file to look for, as defined in the |
142 | * package structure. |
143 | * @return list of files by name, suitable for passing to filePath |
144 | **/ |
145 | QStringList entryList(const QByteArray &key) const; |
146 | |
147 | /** |
148 | * @return true if the item at path exists and is required |
149 | **/ |
150 | bool isRequired(const QByteArray &key) const; |
151 | |
152 | /** |
153 | * @return the mimeTypes associated with the path, if any |
154 | **/ |
155 | QStringList mimeTypes(const QByteArray &key) const; |
156 | |
157 | /** |
158 | * @return the prefix paths inserted between the base path and content entries, in order of priority. |
159 | * When searching for a file, all paths will be tried in order. |
160 | */ |
161 | QStringList contentsPrefixPaths() const; |
162 | |
163 | /** |
164 | * @return preferred package root. This defaults to kpackage/generic/ |
165 | */ |
166 | QString defaultPackageRoot() const; |
167 | |
168 | /** |
169 | * @return true if paths/symlinks outside the package itself should be followed. |
170 | * By default this is set to false for security reasons. |
171 | */ |
172 | bool allowExternalPaths() const; |
173 | |
174 | /** |
175 | * Sets the metadata for the KPackage. This overwrites the current metadata. |
176 | * This should be used in case a kpackage gets loaded by name, based |
177 | * on the path a C++ plugin which has embedded metadata. |
178 | * @since 5.88 |
179 | */ |
180 | void setMetadata(const KPluginMetaData &data); |
181 | |
182 | /** |
183 | * @return the package metadata object. |
184 | */ |
185 | KPluginMetaData metadata() const; |
186 | |
187 | /** |
188 | * @return a hash digest of the contents of the package in hexadecimal form |
189 | * @since 5.21 |
190 | */ |
191 | QByteArray cryptographicHash(QCryptographicHash::Algorithm algorithm) const; |
192 | |
193 | /** |
194 | * Adds a directory to the structure of the package. It is added as |
195 | * a not-required element with no associated mimeTypes. |
196 | * If an entry with the given key already exists, the path |
197 | * is added to it as a search alternative. |
198 | * |
199 | * @param key used as an internal label for this directory |
200 | * @param path the path within the package for this directory |
201 | */ |
202 | void addDirectoryDefinition(const QByteArray &key, const QString &path); |
203 | |
204 | /** |
205 | * Adds a file to the structure of the package. It is added as |
206 | * a not-required element with no associated mimeTypes. |
207 | * If an entry with the given key already exists, the path |
208 | * is added to it as a search alternative. |
209 | * |
210 | * @param key used as an internal label for this file |
211 | * @param path the path within the package for this file |
212 | */ |
213 | void addFileDefinition(const QByteArray &key, const QString &path); |
214 | |
215 | /** |
216 | * Removes a definition from the structure of the package. |
217 | * @param key the internal label of the file or directory to remove |
218 | */ |
219 | void removeDefinition(const QByteArray &key); |
220 | |
221 | /** |
222 | * Sets whether or not a given part of the structure is required or not. |
223 | * The path must already have been added using addDirectoryDefinition |
224 | * or addFileDefinition. |
225 | * |
226 | * @param key the entry within the package |
227 | * @param required true if this entry is required, false if not |
228 | */ |
229 | void setRequired(const QByteArray &key, bool required); |
230 | |
231 | /** |
232 | * Defines the default mimeTypes for any definitions that do not have |
233 | * associated mimeTypes. Handy for packages with only one or predominantly |
234 | * one file type. |
235 | * |
236 | * @param mimeTypes a list of mimeTypes |
237 | **/ |
238 | void setDefaultMimeTypes(const QStringList &mimeTypes); |
239 | |
240 | /** |
241 | * Define mimeTypes for a given part of the structure |
242 | * The path must already have been added using addDirectoryDefinition |
243 | * or addFileDefinition. |
244 | * |
245 | * @param key the entry within the package |
246 | * @param mimeTypes a list of mimeTypes |
247 | **/ |
248 | void setMimeTypes(const QByteArray &key, const QStringList &mimeTypes); |
249 | |
250 | /** |
251 | * Sets the prefixes that all the contents in this package should |
252 | * appear under. This defaults to "contents/" and is added automatically |
253 | * between the base path and the entries as defined by the package |
254 | * structure. Multiple entries can be added. |
255 | * In this case each file request will be searched in all prefixes in order, |
256 | * and the first found will be returned. |
257 | * |
258 | * @param prefix paths the directory prefix to use |
259 | */ |
260 | void setContentsPrefixPaths(const QStringList &prefixPaths); |
261 | |
262 | /** |
263 | * Sets whether or not external paths/symlinks can be followed by a package |
264 | * @param allow true if paths/symlinks outside of the package should be followed, |
265 | * false if they should be rejected. |
266 | */ |
267 | void setAllowExternalPaths(bool allow); |
268 | |
269 | /** |
270 | * Sets preferred package root. |
271 | */ |
272 | void setDefaultPackageRoot(const QString &packageRoot); |
273 | |
274 | /** |
275 | * Sets the fallback package root path |
276 | * If a file won't be found in this package, it will search it in the package |
277 | * with the same structure identified by path |
278 | * It is intended to be used by the packageStructure |
279 | * @param path package root path @see setPath |
280 | */ |
281 | void setFallbackPackage(const KPackage::Package &package); |
282 | |
283 | /** |
284 | * @return The fallback package root path |
285 | */ |
286 | KPackage::Package fallbackPackage() const; |
287 | |
288 | // Content structure description methods |
289 | /** |
290 | * @return all directories registered as part of this Package's structure |
291 | */ |
292 | QList<QByteArray> directories() const; |
293 | |
294 | /** |
295 | * @return all directories registered as part of this Package's required structure |
296 | */ |
297 | QList<QByteArray> requiredDirectories() const; |
298 | |
299 | /** |
300 | * @return all files registered as part of this Package's structure |
301 | */ |
302 | QList<QByteArray> files() const; |
303 | |
304 | /** |
305 | * @return all files registered as part of this Package's required structure |
306 | */ |
307 | QList<QByteArray> requiredFiles() const; |
308 | |
309 | private: |
310 | QExplicitlySharedDataPointer<PackagePrivate> d; |
311 | friend class PackagePrivate; |
312 | }; |
313 | |
314 | } |
315 | |
316 | Q_DECLARE_METATYPE(KPackage::Package) |
317 | #endif |
318 | |