1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "qresourcerelocater_p.h"
5
6#include <QXmlStreamReader>
7#include <QFile>
8#include <QDir>
9
10QT_BEGIN_NAMESPACE
11
12/*!
13 \internal
14 Changes all the paths in resource file \a input so that they are relative to
15 location \a output and writes the result to resource file \a output.
16 */
17int qRelocateResourceFile(const QString &input, const QString &output)
18{
19 enum State {
20 InitialState,
21 InRCC,
22 InResource,
23 InFile
24 };
25 State state = InitialState;
26
27 QString prefix;
28 QString currentFileName;
29 QXmlStreamAttributes fileAttributes;
30
31 QFile file(input);
32 if (!file.open(flags: QIODevice::ReadOnly)) {
33 fprintf(stderr, format: "Cannot open %s for reading.\n", qPrintable(input));
34 return EXIT_FAILURE;
35 }
36
37 QDir inputDirectory = QFileInfo(file).absoluteDir();
38 QDir outputDirectory = QFileInfo(output).absoluteDir();
39
40 QString outputString;
41 QXmlStreamWriter writer(&outputString);
42 writer.setAutoFormatting(true);
43
44 QXmlStreamReader reader(&file);
45 while (!reader.atEnd()) {
46 switch (reader.readNext()) {
47 case QXmlStreamReader::StartDocument: {
48 QStringView version = reader.documentVersion();
49 if (!version.isEmpty())
50 writer.writeStartDocument(version: version.toString());
51 else
52 writer.writeStartDocument();
53 break;
54 }
55 case QXmlStreamReader::EndDocument:
56 writer.writeEndDocument();
57 break;
58 case QXmlStreamReader::StartElement:
59 if (reader.name() == QStringLiteral("RCC")) {
60 if (state != InitialState) {
61 fprintf(stderr, format: "Unexpected RCC tag in line %d\n", int(reader.lineNumber()));
62 return EXIT_FAILURE;
63 }
64 state = InRCC;
65 } else if (reader.name() == QStringLiteral("qresource")) {
66 if (state != InRCC) {
67 fprintf(stderr, format: "Unexpected qresource tag in line %d\n", int(reader.lineNumber()));
68 return EXIT_FAILURE;
69 }
70 state = InResource;
71 QXmlStreamAttributes attributes = reader.attributes();
72 if (attributes.hasAttribute(QStringLiteral("prefix")))
73 prefix = attributes.value(QStringLiteral("prefix")).toString();
74 if (!prefix.startsWith(c: QLatin1Char('/')))
75 prefix.prepend(c: QLatin1Char('/'));
76 if (!prefix.endsWith(c: QLatin1Char('/')))
77 prefix.append(c: QLatin1Char('/'));
78 } else if (reader.name() == QStringLiteral("file")) {
79 if (state != InResource) {
80 fprintf(stderr, format: "Unexpected file tag in line %d\n", int(reader.lineNumber()));
81 return EXIT_FAILURE;
82 }
83 state = InFile;
84 fileAttributes = reader.attributes();
85 continue;
86 }
87 writer.writeStartElement(qualifiedName: reader.name().toString());
88 writer.writeAttributes(attributes: reader.attributes());
89 continue;
90
91 case QXmlStreamReader::EndElement:
92 if (reader.name() == QStringLiteral("file")) {
93 if (state != InFile) {
94 fprintf(stderr, format: "Unexpected end of file tag in line %d\n", int(reader.lineNumber()));
95 return EXIT_FAILURE;
96 }
97 state = InResource;
98 continue;
99 } else if (reader.name() == QStringLiteral("qresource")) {
100 if (state != InResource) {
101 fprintf(stderr, format: "Unexpected end of qresource tag in line %d\n", int(reader.lineNumber()));
102 return EXIT_FAILURE;
103 }
104 state = InRCC;
105 } else if (reader.name() == QStringLiteral("RCC")) {
106 if (state != InRCC) {
107 fprintf(stderr, format: "Unexpected end of RCC tag in line %d\n", int(reader.lineNumber()));
108 return EXIT_FAILURE;
109 }
110 state = InitialState;
111 }
112 writer.writeEndElement();
113 continue;
114
115 case QXmlStreamReader::Characters:
116 if (reader.isWhitespace())
117 break;
118 if (state != InFile)
119 return EXIT_FAILURE;
120 currentFileName = reader.text().toString();
121 if (currentFileName.isEmpty())
122 continue;
123
124 writer.writeStartElement(QStringLiteral("file"));
125
126 if (!fileAttributes.hasAttribute(QStringLiteral("alias")))
127 fileAttributes.append(QStringLiteral("alias"), value: currentFileName);
128
129 currentFileName = inputDirectory.absoluteFilePath(fileName: currentFileName);
130 currentFileName = outputDirectory.relativeFilePath(fileName: currentFileName);
131
132 writer.writeAttributes(attributes: fileAttributes);
133 writer.writeCharacters(text: currentFileName);
134 writer.writeEndElement();
135 continue;
136
137 default: break;
138 }
139 }
140
141 QFile outputFile(output);
142 if (!outputFile.open(flags: QIODevice::WriteOnly | QIODevice::Truncate)) {
143 fprintf(stderr, format: "Cannot open %s for writing.\n", qPrintable(output));
144 return EXIT_FAILURE;
145 }
146 const QByteArray outputStringUtf8 = outputString.toUtf8();
147 if (outputFile.write(data: outputStringUtf8) != outputStringUtf8.size())
148 return EXIT_FAILURE;
149
150 outputFile.close();
151 if (outputFile.error() != QFileDevice::NoError)
152 return EXIT_FAILURE;
153
154
155 return EXIT_SUCCESS;
156}
157
158QT_END_NAMESPACE
159

source code of qtdeclarative/src/qmlcompiler/qresourcerelocater.cpp