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 QString errorMessage;
64 int errorLine;
65 int errorColumn;
66 if (!manifestDocument.setContent(device, true, &errorMessage, &errorLine, &errorColumn)) {
67 warnKrita << "Error parsing manifest" << errorMessage
68 << "line" << errorLine
69 << "column" << errorColumn;
70 return false;
71 }
72
73 QDomElement root = manifestDocument.documentElement();
74 if (root.localName() != "manifest" || root.namespaceURI() != KoXmlNS::manifest) {
75 return false;
76 }
77
78 QDomElement e = root.firstChildElement("file-entry");
79 for (; !e.isNull(); e = e.nextSiblingElement("file-entry")) {
80 if (!parseFileEntry(e)) {
81 warnKrita << "Skipping invalid manifest entry"
82 << "line" << e.lineNumber();
83 }
84 }
85
86 return true;
87}
88
90{
91 if (e.localName() != "file-entry" || e.namespaceURI() != KoXmlNS::manifest) {
92 return false;
93 }
94
95 QString fullPath = e.attributeNS(KoXmlNS::manifest, "full-path");
96 QString mediaType = e.attributeNS(KoXmlNS::manifest, "media-type");
97 QString md5sum = e.attributeNS(KoXmlNS::manifest, "md5sum");
98 QString version = e.attributeNS(KoXmlNS::manifest, "version");
99
100 if (fullPath == "/" && mediaType == "application/x-krita-resourcebundle") {
101 // The manifest always contains an entry for the bundle root.
102 // This is not a resource, so skip it without indicating failure.
103 return true;
104 } else if (fullPath.isNull() || mediaType.isNull() || md5sum.isNull()) {
105 return false;
106 }
107
108 QStringList tagList;
109 QDomElement t = e.firstChildElement("tags")
110 .firstChildElement("tag");
111 for (; !t.isNull(); t = t.nextSiblingElement("tag")) {
112 QString tag = t.text();
113 if (!tag.isNull()) {
114 tagList.append(tag);
115 }
116 }
117
118 addResource(mediaType, fullPath, tagList, QByteArray::fromHex(md5sum.toLatin1()), -1);
119 return true;
120}
121
122bool KoResourceBundleManifest::save(QIODevice *device)
123{
124 if (!device->isOpen()) {
125 if (!device->open(QIODevice::WriteOnly)) {
126 return false;
127 }
128 }
129 KoXmlWriter manifestWriter(device);
130 manifestWriter.startDocument("manifest:manifest");
131 manifestWriter.startElement("manifest:manifest");
132 manifestWriter.addAttribute("xmlns:manifest", KoXmlNS::manifest);
133 manifestWriter.addAttribute("manifest:version", "1.2");
134 manifestWriter.addManifestEntry("/", "application/x-krita-resourcebundle");
135
136 Q_FOREACH (QString resourceType, m_resources.keys()) {
137 Q_FOREACH (const ResourceReference &resource, m_resources[resourceType].values()) {
138 manifestWriter.startElement("manifest:file-entry");
139 manifestWriter.addAttribute("manifest:media-type", resourceTypeToManifestType(resourceType));
140 // we cannot just use QFileInfo(resource.resourcePath).fileName() because it would cut off the subfolder
141 // but the resourcePath is already correct, so let's just add the resourceType
142 manifestWriter.addAttribute("manifest:full-path", resourceTypeToManifestType(resourceType) + "/" + resource.filenameInBundle);
143 manifestWriter.addAttribute("manifest:md5sum", resource.md5sum);
144 if (!resource.tagList.isEmpty()) {
145 manifestWriter.startElement("manifest:tags");
146 Q_FOREACH (const QString tag, resource.tagList) {
147 manifestWriter.startElement("manifest:tag");
148 manifestWriter.addTextNode(tag);
149 manifestWriter.endElement();
150 }
151 manifestWriter.endElement();
152 }
153 manifestWriter.endElement();
154 }
155 }
156
157 manifestWriter.endElement();
158 manifestWriter.endDocument();
159
160 return true;
161}
162
163void KoResourceBundleManifest::addResource(const QString &fileTypeName, const QString &fileName, const QStringList &fileTagList, const QString &md5, const int resourceId, const QString filenameInBundle)
164{
165 ResourceReference ref(fileName, fileTagList, fileTypeName, md5, resourceId, filenameInBundle);
166 if (!m_resources.contains(fileTypeName)) {
167 m_resources[fileTypeName] = QMap<QString, ResourceReference>();
168 }
169 m_resources[fileTypeName].insert(fileName, ref);
170}
171
173{
174 if (m_resources.contains(resource.fileTypeName)) {
175 if (m_resources[resource.fileTypeName].contains(resource.resourcePath)) {
176 m_resources[resource.fileTypeName].take(resource.resourcePath);
177 }
178 }
179}
180
182{
183 return m_resources.keys();
184}
185
187{
188 QSet<QString> tags;
189 Q_FOREACH (const QString &type, m_resources.keys()) {
190 Q_FOREACH (const ResourceReference &ref, m_resources[type].values()) {
191 tags += QSet<QString>(ref.tagList.begin(), ref.tagList.end());
192 }
193 }
194 return QStringList(tags.begin(), tags.end());
195 }
196
198{
199 QList<ResourceReference> resources;
200
201 if (type.isEmpty()) {
202 // If no type is specified we return all the resources.
203 Q_FOREACH (const QString &type, m_resources.keys()) {
204 resources += m_resources[type].values();
205 }
206 } else if (m_resources.contains(type)) {
207 resources = m_resources[type].values();
208 }
209
210 return resources;
211}
212
214{
216 Q_FOREACH (const QString &type, m_resources.keys()) {
217 if (m_resources[type].contains(fileName)) {
218 m_resources[type].remove(fileName);
219 }
220 }
221}
222
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