1 /* This file is part of the KDE project
2 
3    Copyright (C) 2013 Inge Wallin <inge@lysator.liu.se>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifndef KOXMLSTREAMREADER_H
22 #define KOXMLSTREAMREADER_H
23 
24 
25 #include "KoXmlStreamReader.h"
26 
27 #include <QXmlStreamReader>
28 #include <QStringRef>
29 #include <QVector>
30 #include <QSharedData>
31 
32 #include "koodf2_export.h"
33 
34 
35 class QByteArray;
36 class QString;
37 class QIODevice;
38 
39 class KoXmlStreamAttributes;
40 
41 
42 /**
43  * @brief An XML stream reader based on QXmlStreamReader and with namespace handling better suited to use for ODF in Calligra.
44  *
45  * Opendocument uses an XML encoding which makes heavy use of
46  * namespaces. So normally you would want to compare the qualified
47  * name when accessing tagnames and attributes.
48  *
49  * However, in QXmlStreamReader you have to either make an explicit
50  * comparison with the namespace URI for every element and attribute
51  * or risk that documents that use the correct namespaces but not the
52  * normal namespace prefixes are wrongly interpreted.  This is because
53  * the prefix (e.g. "fo" in "fo:border-width") is declared at the
54  * beginning of the document using a namespace declaration attribute
55  * such as: xmlns:fo="http://www.w3.org/1999/XSL/Format". In this case
56  * xmlns:fo could just as well be xmlns:xxx which makes the expected
57  * fo:border-width become xxx:border-width in the rest of this
58  * document.
59  *
60  * However, it is extremely rare to find document that uses such
61  * non-standard namespace prefixes. This gives us the opportunity to
62  * optimize for the common case, which is exactly what
63  * KoXmlStreamReader does.
64  *
65  * The way to use this class is to tell it which namespaces and
66  * prefixes that you expect before you open the XML stream. Then it
67  * checks if the namespaces and prefixes in the document are the same
68  * as the expected ones.  If they are in fact the same, the document
69  * is pronounced "sound", and for the rest of the processing you can
70  * use the qualified name with the expected prefix ("fo:border-width")
71  * with the maximum performance.
72  *
73  * If the namespace(s) in the document are the expected ones but the
74  * prefix(es) are not, you can still compare the qualified name to
75  * your expected ones.  But in this case the document is deemed
76  * "unsound" and for every access to attributes or calls to
77  * qualifiedName(), KoXmlStreamReader will rewrite the actual name in
78  * the document to become what you expect.  The functions
79  * namespaceUri() and name() are not affected, only the prefixes.
80  */
81 class KOODF2_EXPORT KoXmlStreamReader : public QXmlStreamReader
82 {
83     friend class KoXmlStreamAttribute;
84     friend class KoXmlStreamAttributes;
85 
86 public:
87     KoXmlStreamReader();
88     explicit KoXmlStreamReader(QIODevice *device);
89     explicit KoXmlStreamReader(const QByteArray &data);
90     explicit KoXmlStreamReader(const QString &data);
91     explicit KoXmlStreamReader(const char *data);
92 
93     ~KoXmlStreamReader();
94 
95     void clear();
96 
97     void addExpectedNamespace(const QString &prefix, const QString &namespaceUri);
98     void addExtraNamespace(const QString &prefix, const QString &namespaceUri);
99 
100     // --------------------------------
101     // Reimplemented from QXmlStreamReader
102 
103     QStringRef prefix() const;
104     QStringRef qualifiedName() const;
105     void setDevice(QIODevice *device);
106     KoXmlStreamAttributes attributes() const;
107 
108 private:
109     // No copying
110     KoXmlStreamReader(const KoXmlStreamReader &other);
111     KoXmlStreamReader &operator=(const KoXmlStreamReader &other);
112 
113     // Only for friend classes KoXmlStreamAttributes and KoXmlStreamAttribute.
114     bool isSound() const;
115 
116     class Private;
117     Private * const d;
118 };
119 
120 
121 /**
122  * @brief KoXmlStreamAttribute is a source-compatible replacement for QXmlStreamAttribute.
123  *
124  * In addition to the API from QXmlStreamAttribute, it offers the same
125  * advantages that KoXmlStreamReader does over QXmlStreamReader: when
126  * asked for the qualified name of an attribute it will return the
127  * expected one even if the prefix declared in the namespace
128  * declaration of the document is different.
129  *
130  * @see KoXmlStreamReader
131  */
132 class KOODF2_EXPORT KoXmlStreamAttribute
133 {
134     friend class QVector<KoXmlStreamAttribute>;       // For the default constructor
135     friend class KoXmlStreamAttributes;               // For the normal constructor
136     friend class KoXmlStreamReader;
137  public:
138     ~KoXmlStreamAttribute();
139 
140     // API taken from QXmlStreamAttribute
141     bool       isDefault() const;
142     QStringRef name() const;
143     QStringRef namespaceUri() const;
144     QStringRef prefix() const;
145     QStringRef qualifiedName() const;
146     QStringRef value() const;
147 
148     bool operator==(const KoXmlStreamAttribute &other) const;
149     bool operator!=(const KoXmlStreamAttribute &other) const;
150     KoXmlStreamAttribute &operator=(const KoXmlStreamAttribute &other);
151 
152  private:
153     // Only for friend classes.
154     KoXmlStreamAttribute();
155     KoXmlStreamAttribute(const KoXmlStreamAttribute &other);
156     KoXmlStreamAttribute(const QXmlStreamAttribute *attr, const KoXmlStreamReader *reader);
157 
158     class Private;
159     Private * const d;
160 };
161 
162 
163 /**
164  * @brief KoXmlStreamAttributes is a mostly source-compatible replacement for QXmlStreamAttributes.
165  *
166  * All the convenience functions of KoXmlStreamAttributes work exactly
167  * like the counterparts of QXmlStreamAttributes but they give the
168  * expected prefix for the registered expected namespaces.
169  *
170  * Not all functions from QVector are implemented but the ones that
171  * make sense for this read-only class are. This class can only be
172  * used in connection with KoXmlStreamReader.
173  *
174  * @see KoXmlStreamReader
175  */
176 class KOODF2_EXPORT KoXmlStreamAttributes
177 {
178     friend class KoXmlStreamReader;
179 
180  public:
181     typedef const KoXmlStreamAttribute *const_iterator;
182 
183     KoXmlStreamAttributes(const KoXmlStreamAttributes &other);
184     ~KoXmlStreamAttributes();
185 
186     KoXmlStreamAttributes &operator=(const KoXmlStreamAttributes &other);
187 
188     // Relevant parts of the QVector API
189     const KoXmlStreamAttribute &at(int i) const;
190     int size() const;
191     KoXmlStreamAttribute value(int i) const;
192     const KoXmlStreamAttribute &operator[](int i) const;
193     const_iterator begin() const;
194     const_iterator end() const;
195 
196     // Convenience functions taken from QXmlStreamAttributes API
197     void        append(const QString &namespaceUri, const QString &name, const QString &value);
198     void        append(const QXmlStreamAttribute &attribute);
199     void        append(const QString &qualifiedName, const QString &value);
200     bool        hasAttribute(const QString &qualifiedName) const;
201     bool        hasAttribute(const QLatin1String &qualifiedName) const;
202     bool        hasAttribute ( const QString & namespaceUri, const QString & name ) const;
203     QStringRef  value ( const QString & namespaceUri, const QString & name ) const;
204     QStringRef  value ( const QString & namespaceUri, const QLatin1String & name ) const;
205     QStringRef  value ( const QLatin1String & namespaceUri, const QLatin1String & name ) const;
206     QStringRef  value(const QString &qualifiedName) const;
207     QStringRef  value(const QLatin1String &qualifiedName) const;
208 
209  private:
210     // Only available from friend class KoXmlStreamReader.
211     KoXmlStreamAttributes(const KoXmlStreamReader *r, const QXmlStreamAttributes &qAttrs);
212 
213     // This class is implicitly shared.
214     class Private;
215     QSharedDataPointer<Private> d;
216 };
217 
218 
219 void KOODF2_EXPORT prepareForOdf(KoXmlStreamReader &reader);
220 
221 
222 #endif /* KOXMLSTREAMREADER_H */
223