Krita Source Code Documentation
Loading...
Searching...
No Matches
KoResourceBundleManifest.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 SPDX-FileCopyrightText: 2014 Victor Lafon <metabolic.ewilan@hotmail.fr>
3
4 SPDX-License-Identifier: LGPL-2.1-or-later
5*/
7
8#include <QList>
9#include <QSet>
10#include <QString>
11#include <QDomDocument>
12#include <QDomElement>
13#include <QDomNode>
14#include <QDomNodeList>
15#include <QFileInfo>
16
17#include <KoXmlNS.h>
18#include <KoXmlWriter.h>
19
20#include <kis_debug.h>
21
22#include "KisResourceTypes.h"
23
24QString resourceTypeToManifestType(const QString &type) {
25 if (type.startsWith("ko_")) {
26 return type.mid(3);
27 }
28 else if (type.startsWith("kis_")) {
29 return type.mid(4);
30 }
31 else {
32 return type;
33 }
34}
35
36QString manifestTypeToResourceType(const QString &type) {
38 return "ko_" + type;
39 }
40 else {
41 return "kis_" + type;
42 }
43}
44
48
52
53bool KoResourceBundleManifest::load(QIODevice *device)
54{
55 m_resources.clear();
56 if (!device->isOpen()) {
57 if (!device->open(QIODevice::ReadOnly)) {
58 return false;
59 }
60 }
61
62 QDomDocument manifestDocument;
63#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
64 QString errorMessage;
65 int errorLine;
66 int errorColumn;
67 if (!manifestDocument.setContent(device, true, &errorMessage, &errorLine, &errorColumn)) {
68 warnKrita << "Error parsing manifest" << errorMessage
69 << "line" << errorLine
70 << "column" << errorColumn;
71#else
72 QDomDocument::ParseResult result = manifestDocument.setContent(device, QDomDocument::ParseOption::UseNamespaceProcessing);
73 if (!result) {
74 warnKrita << "Error parsing manifest" << result.errorMessage
75 << "line" << result.errorLine
76 << "column" << result.errorColumn;
77#endif
78 return false;
79 }
80
81 QDomElement root = manifestDocument.documentElement();
82 if (root.localName() != "manifest" || root.namespaceURI() != KoXmlNS::manifest) {
83 return false;
84 }
85
86 QDomElement e = root.firstChildElement("file-entry");
87 for (; !e.isNull(); e = e.nextSiblingElement("file-entry")) {
88 if (!parseFileEntry(e)) {
89 warnKrita << "Skipping invalid manifest entry"
90 << "line" << e.lineNumber();
91 }
92 }
93
94 return true;
95}
96
98{
99 if (e.localName() != "file-entry" || e.namespaceURI() != KoXmlNS::manifest) {
100 return false;
101 }
102
103 QString fullPath = e.attributeNS(KoXmlNS::manifest, "full-path");
104 QString mediaType = e.attributeNS(KoXmlNS::manifest, "media-type");
105 QString md5sum = e.attributeNS(KoXmlNS::manifest, "md5sum");
106 QString version = e.attributeNS(KoXmlNS::manifest, "version");
107
108 if (fullPath == "/" && mediaType == "application/x-krita-resourcebundle") {
109 // The manifest always contains an entry for the bundle root.
110 // This is not a resource, so skip it without indicating failure.
111 return true;
112 } else if (fullPath.isNull() || mediaType.isNull() || md5sum.isNull()) {
113 return false;
114 }
115
116 QStringList tagList;
117 QDomElement t = e.firstChildElement("tags")
118 .firstChildElement("tag");
119 for (; !t.isNull(); t = t.nextSiblingElement("tag")) {
120 QString tag = t.text();
121 if (!tag.isNull()) {
122 tagList.append(tag);
123 }
124 }
125
126 addResource(mediaType, fullPath, tagList, QByteArray::fromHex(md5sum.toLatin1()), -1);
127 return true;
128}
129
130bool KoResourceBundleManifest::save(QIODevice *device)
131{
132 if (!device->isOpen()) {
133 if (!device->open(QIODevice::WriteOnly)) {
134 return false;
135 }
136 }
137 KoXmlWriter manifestWriter(device);
138 manifestWriter.startDocument("manifest:manifest");
139 manifestWriter.startElement("manifest:manifest");
140 manifestWriter.addAttribute("xmlns:manifest", KoXmlNS::manifest);
141 manifestWriter.addAttribute("manifest:version", "1.2");
142 manifestWriter.addManifestEntry("/", "application/x-krita-resourcebundle");
143
144 Q_FOREACH (QString resourceType, m_resources.keys()) {
145 Q_FOREACH (const ResourceReference &resource, m_resources[resourceType].values()) {
146 manifestWriter.startElement("manifest:file-entry");
147 manifestWriter.addAttribute("manifest:media-type", resourceTypeToManifestType(resourceType));
148 // we cannot just use QFileInfo(resource.resourcePath).fileName() because it would cut off the subfolder
149 // but the resourcePath is already correct, so let's just add the resourceType
150 manifestWriter.addAttribute("manifest:full-path", resourceTypeToManifestType(resourceType) + "/" + resource.filenameInBundle);
151 manifestWriter.addAttribute("manifest:md5sum", resource.md5sum);
152 if (!resource.tagList.isEmpty()) {
153 manifestWriter.startElement("manifest:tags");
154 Q_FOREACH (const QString tag, resource.tagList) {
155 manifestWriter.startElement("manifest:tag");
156 manifestWriter.addTextNode(tag);
157 manifestWriter.endElement();
158 }
159 manifestWriter.endElement();
160 }
161 manifestWriter.endElement();
162 }
163 }
164
165 manifestWriter.endElement();
166 manifestWriter.endDocument();
167
168 return true;
169}
170
171void KoResourceBundleManifest::addResource(const QString &fileTypeName, const QString &fileName, const QStringList &fileTagList, const QString &md5, const int resourceId, const QString filenameInBundle)
172{
173 ResourceReference ref(fileName, fileTagList, fileTypeName, md5, resourceId, filenameInBundle);
174 if (!m_resources.contains(fileTypeName)) {
175 m_resources[fileTypeName] = QMap<QString, ResourceReference>();
176 }
177 m_resources[fileTypeName].insert(fileName, ref);
178}
179
181{
182 if (m_resources.contains(resource.fileTypeName)) {
183 if (m_resources[resource.fileTypeName].contains(resource.resourcePath)) {
184 m_resources[resource.fileTypeName].take(resource.resourcePath);
185 }
186 }
187}
188
190{
191 return m_resources.keys();
192}
193
195{
196 QSet<QString> tags;
197 Q_FOREACH (const QString &type, m_resources.keys()) {
198 Q_FOREACH (const ResourceReference &ref, m_resources[type].values()) {
199 tags += QSet<QString>(ref.tagList.begin(), ref.tagList.end());
200 }
201 }
202 return QStringList(tags.begin(), tags.end());
203 }
204
206{
207 QList<ResourceReference> resources;
208
209 if (type.isEmpty()) {
210 // If no type is specified we return all the resources.
211 Q_FOREACH (const QString &type, m_resources.keys()) {
212 resources += m_resources[type].values();
213 }
214 } else if (m_resources.contains(type)) {
215 resources = m_resources[type].values();
216 }
217
218 return resources;
219}
220
222{
224 Q_FOREACH (const QString &type, m_resources.keys()) {
225 if (m_resources[type].contains(fileName)) {
226 m_resources[type].remove(fileName);
227 }
228 }
229}
230
QList< QString > QStringList
QString manifestTypeToResourceType(const QString &type)
QString resourceTypeToManifestType(const QString &type)
void removeFile(QString fileName)
removeFile : remove a file from the manifest
bool save(QIODevice *device)
save the ResourceBundleManifest to the given device
virtual ~KoResourceBundleManifest()
~ResourceBundleManifest : Dtor
bool parseFileEntry(const QDomElement &e)
KoResourceBundleManifest()
ResourceBundleManifest : Ctor.
bool load(QIODevice *device)
load the ResourceBundleManifest from the given device
QMap< QString, QMap< QString, ResourceReference > > m_resources
void removeResource(ResourceReference &resource)
void addResource(const QString &fileType, const QString &fileName, const QStringList &tagFileList, const QString &md5, const int resourceId=-1, const QString filenameInBundle="")
addTag : Add a file tag as a child of the fileType tag.
QList< ResourceReference > files(const QString &type=QString()) const
static const QString manifest
Definition KoXmlNS.h:35
void addManifestEntry(const QString &fullPath, const QString &mediaType)
void startElement(const char *tagName, bool indentInside=true)
void endDocument()
Call this to terminate an XML document.
void startDocument(const char *rootElemName, const char *publicId=0, const char *systemId=0)
void addTextNode(const QString &str)
void endElement()
void addAttribute(const char *attrName, const QString &value)
Definition KoXmlWriter.h:61
#define warnKrita
Definition kis_debug.h:87
const QString Palettes
const QString Patterns
const QString Gradients