2
* This file is part of Office 2007 Filters for KOffice
4
* Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
6
* Contact: Suresh Chande suresh.chande@nokia.com
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public License
10
* version 2.1 as published by the Free Software Foundation.
12
* This library is distributed in the hope that it will be useful, but
13
* WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24
#ifndef MSOOXMLREADER_P_H
25
#define MSOOXMLREADER_P_H
27
#ifndef MSOOXML_CURRENT_CLASS
28
#error Please include MsooXmlReader_p.h after defining MSOOXML_CURRENT_CLASS and MSOOXML_CURRENT_NS!
31
#define PASTE2(a, b) a##b
32
#define PASTE(a, b) PASTE2( a, b) // indirection needed because only function-like macro parameters can be pasted
34
#define PASTE3_(a, b, c) a##b##c
35
#define PASTE3(a, b, c) PASTE3_( a, b, c) // indirection needed because only function-like macro parameters can be pasted
37
#define JOIN2(a, b) a#b
38
#define JOIN(a, b) JOIN2( a, b) // indirection needed because only function-like macro parameters can be pasted
40
#define STRINGIFY(s) JOIN("", s)
42
//! Used to pass context: creates enum value {el}_{CURRENT_EL}
43
#define PASS_CONTEXT(el) PASTE3(el, _, CURRENT_EL)
45
#define TRY_READ_WITH_ARGS_INTERNAL(name, args, context) \
47
RETURN_IF_ERROR( read_ ## name (context) )
49
#define TRY_READ_WITH_ARGS(name, args) \
50
TRY_READ_WITH_ARGS_INTERNAL(name, m_read_ ## name ## _args = args,)
52
#define TRY_READ_WITH_ARGS_IN_CONTEXT(name, args) \
53
TRY_READ_WITH_ARGS_INTERNAL(name, m_read_ ## name ## _args = args, PASS_CONTEXT(name))
55
#define TRY_READ(name) \
56
TRY_READ_WITH_ARGS_INTERNAL(name, ,)
58
#define TRY_READ_IN_CONTEXT(name) \
59
TRY_READ_WITH_ARGS_INTERNAL(name, , PASS_CONTEXT(name))
61
#ifdef MSOOXML_CURRENT_NS
62
# define QUALIFIED_NAME(name) \
63
JOIN(MSOOXML_CURRENT_NS ":",name)
65
# define QUALIFIED_NAME(name) \
70
# define PUSH_NAME_INTERNAL
71
# define POP_NAME_INTERNAL
73
//! returns caller name at the current scope or "top level"
74
#define CALL_STACK_TOP_NAME (m_callsNamesDebug.isEmpty() \
75
? QByteArray("top level") : m_callsNamesDebug.top()).constData()
77
//! put at beginning of each read_*() method on call stack, only in debug mode
78
# define PUSH_NAME_INTERNAL \
79
kDebug() << CALL_STACK_TOP_NAME << "==>" << QUALIFIED_NAME(CURRENT_EL); \
80
m_callsNamesDebug.push(STRINGIFY(CURRENT_EL));
81
//! put at the end of each read_*() method on call stack, only in debug mode
82
# define POP_NAME_INTERNAL \
83
m_callsNamesDebug.pop(); \
84
kDebug() << CALL_STACK_TOP_NAME << "<==" << QUALIFIED_NAME(CURRENT_EL);
87
#define READ_PROLOGUE2(method) \
89
if (!expectEl(QUALIFIED_NAME(CURRENT_EL))) { \
90
return KoFilter::WrongFormat; \
93
#define READ_PROLOGUE \
94
READ_PROLOGUE2(CURRENT_EL)
96
#define READ_EPILOGUE_WITHOUT_RETURN \
98
if (!expectElEnd(QUALIFIED_NAME(CURRENT_EL))) { \
99
kDebug() << "READ_EPILOGUE:" << QUALIFIED_NAME(CURRENT_EL) << "not found!"; \
100
return KoFilter::WrongFormat; \
102
kDebug() << "/READ_EPILOGUE_WITHOUT_RETURN";
104
#define READ_EPILOGUE \
105
kDebug() << "READ_EPILOGUE"; \
106
READ_EPILOGUE_WITHOUT_RETURN \
109
#define BREAK_IF_END_OF_QSTRING(name) \
110
kDebug() << "BREAK_IF_END_OF" << name << "found:" << qualifiedName(); \
111
if (isEndElement() && qualifiedName() == name) { \
115
#define BREAK_IF_END_OF(name) \
116
BREAK_IF_END_OF_QSTRING(QLatin1String(QUALIFIED_NAME(name)))
118
//inline bool aaaa(const char * aa) { kDebug() << "aa" << aa; return true; }
120
#define QUALIFIED_NAME_IS(name) \
121
(/*aaaa(STRINGIFY(name)) &&*/ qualifiedName() == QLatin1String(QUALIFIED_NAME(name)))
123
#define TRY_READ_IF_INTERNAL(name, context) \
124
if (QUALIFIED_NAME_IS(name)) { \
125
if (!isStartElement()) { /* sanity check */ \
126
raiseError(i18n("Start element \"%1\" expected, found \"%2\"", \
127
QLatin1String(STRINGIFY(name)), tokenString())); \
128
return KoFilter::WrongFormat; \
130
kDebug() << "TRY_READ_IF " STRINGIFY(name) " started"; \
131
TRY_READ_WITH_ARGS_INTERNAL(name, , context) \
132
kDebug() << "TRY_READ_IF " STRINGIFY(name) " finished"; \
135
#define TRY_READ_IF_IN_CONTEXT_INTERNAL(name, context) \
136
TRY_READ_IF_INTERNAL(name, context)
138
//! Tries to read element @a name by entering into read_{name} function.
139
//! Must be enclosed within if (isStartElement()), otherwise error will be returned.
140
#define TRY_READ_IF_IN_CONTEXT(name) \
141
TRY_READ_IF_IN_CONTEXT_INTERNAL(name, PASS_CONTEXT(name))
143
#define TRY_READ_IF(name) \
144
TRY_READ_IF_IN_CONTEXT_INTERNAL(name,)
146
#define ELSE_TRY_READ_IF(name) \
147
else TRY_READ_IF_IN_CONTEXT_INTERNAL(name,)
149
#define ELSE_TRY_READ_IF_IN_CONTEXT(name) \
150
else TRY_READ_IF_IN_CONTEXT_INTERNAL(name, PASS_CONTEXT(name))
152
#define TRY_READ_IF_NS_INTERNAL(ns, name) \
153
if (qualifiedName() == QLatin1String(JOIN(STRINGIFY(ns) ":", name))) { \
154
kDebug() << "TRY_READ_IF_NS " JOIN(STRINGIFY(ns) ":", name) " started"; \
156
kDebug() << "TRY_READ_IF_NS " JOIN(STRINGIFY(ns) ":", name) " finished"; \
159
//! Like TRY_READ_IF() but namespace for explicit namespace @a ns.
160
#define TRY_READ_IF_NS(ns, name) \
161
if (!isStartElement()) { /* sanity check */ \
162
raiseError(i18n("Start element \"%1\" expected, found \"%2\"", QLatin1String(JOIN(STRINGIFY(ns) ":", name)), tokenString())); \
163
return KoFilter::WrongFormat; \
165
else TRY_READ_IF_NS_INTERNAL(ns, name)
167
#define ELSE_TRY_READ_IF_NS(ns, name) \
168
else TRY_READ_IF_NS_INTERNAL(ns, name)
170
#define ELSE_WRONG_FORMAT \
172
return KoFilter::WrongFormat; \
175
#define ELSE_WRONG_FORMAT_DEBUG(dbg) \
178
return KoFilter::WrongFormat; \
181
//! Reads optional attribute of name @a atrname and allocates variable of the same name.
182
/*! Requires the following line to be present above:
184
const QXmlStreamAttributes attrs( attributes() );
187
#define TRY_READ_ATTR(atrname) \
188
QString atrname( attrs.value(QUALIFIED_NAME(atrname)).toString() );
190
//! Reads optional attribute of name @a atrname into the variable @a destination.
191
/*! Requires the following line to be present above:
193
const QXmlStreamAttributes attrs( attributes() );
196
#define TRY_READ_ATTR_INTO(atrname, destination) \
197
destination = attrs.value(QUALIFIED_NAME(atrname)).toString(); \
198
kDebug() << "TRY_READ_ATTR_INTO: " STRINGIFY(destination) << "=" << destination;
200
//! Reads optional attribute of name @a atrname with explicitly specified namespace @a ns.
201
/*! Creates QString variable with name \<ns\>_\<atrame\>
203
/*! Requires the following line to be present above:
205
const QXmlStreamAttributes attrs( attributes() );
208
#define TRY_READ_ATTR_WITH_NS(ns, atrname) \
209
QString PASTE3(ns, _, atrname)( attrs.value(JOIN(STRINGIFY(ns) ":", atrname)).toString() );
211
//! Reads optional attribute of name @a atrname with explicitly specified namespace @a ns
212
//! into the variable @a destination.
213
/*! Requires the following line to be present above:
215
const QXmlStreamAttributes attrs( attributes() );
218
#define TRY_READ_ATTR_WITH_NS_INTO(ns, atrname, destination) \
219
destination = attrs.value(JOIN(STRINGIFY(ns) ":", atrname)).toString(); \
220
kDebug() << "TRY_READ_ATTR_WITH_NS_INTO: " STRINGIFY(destination) << "=" << destination;
222
inline QString atrToString(const QXmlStreamAttributes& attrs, const char* atrname)
224
const QStringRef v(attrs.value(atrname));
225
return v.isNull() ? QString() : v.toString();
228
//! Reads optional attribute of name @a atrname without namespace.
229
/*! Creates QString variable with name \<atrname\>
231
/*! Requires the following line to be present above:
233
const QXmlStreamAttributes attrs( attributes() );
236
#define TRY_READ_ATTR_WITHOUT_NS(atrname) \
237
QString atrname( atrToString(attrs, STRINGIFY(atrname)) );
239
//! Reads required attribute of name @a atrname and allocates variable of the same name
240
//! If there is no such attribute, returns KoFilter::WrongFormat.
241
/*! Requires the following line to be present above:
243
const QXmlStreamAttributes attrs( attributes() );
246
#define READ_ATTR(atrname) \
248
if (attrs.hasAttribute(QUALIFIED_NAME(atrname))) { \
249
atrname = attrs.value(QUALIFIED_NAME(atrname)).toString(); \
251
ELSE_WRONG_FORMAT_DEBUG( "READ_ATTR: " QUALIFIED_NAME(atrname) " not found" )
253
//! Like @ref READ_ATTR(atrname) but reads the attribute into the variable @a destination.
254
#define READ_ATTR_INTO(atrname, destination) \
255
if (attrs.hasAttribute(QUALIFIED_NAME(atrname))) { \
256
destination = attrs.value(QUALIFIED_NAME(atrname)).toString(); \
258
ELSE_WRONG_FORMAT_DEBUG( "READ_ATTR_INTO: " QUALIFIED_NAME(atrname) " not found" )
260
//! Reads required attribute of name @a atrname with explicitly specified namespace @a ns
261
/*! into the variable @a destination.
263
/*! Requires the following line to be present above:
265
const QXmlStreamAttributes attrs( attributes() );
268
#define READ_ATTR_WITH_NS_INTO(ns, atrname, destination) \
269
if (attrs.hasAttribute(JOIN(STRINGIFY(ns) ":", atrname))) { \
270
destination = attrs.value(JOIN(STRINGIFY(ns) ":", atrname)).toString(); \
272
ELSE_WRONG_FORMAT_DEBUG( "READ_ATTR_WITH_NS_INTO: " JOIN(STRINGIFY(ns) ":", atrname) " not found" )
274
//! Reads required attribute of name @a atrname with explicitly specified namespace @a ns.
275
/*! Creates QString variable with name \<ns\>_\<atrame\>
277
/*! Requires the following line to be present above:
279
const QXmlStreamAttributes attrs( attributes() );
282
#define READ_ATTR_WITH_NS(ns, atrname) \
283
QString PASTE3(ns, _, atrname); \
284
if (attrs.hasAttribute(JOIN(STRINGIFY(ns) ":", atrname))) { \
285
PASTE3(ns, _, atrname) = attrs.value(JOIN(STRINGIFY(ns) ":", atrname)).toString(); \
287
ELSE_WRONG_FORMAT_DEBUG( "READ_ATTR_WITH_NS: " JOIN(STRINGIFY(ns) ":", atrname) " not found" )
289
//! Reads required attribute of name @a atrname without namespace.
290
/*! Creates QString variable with name \<atrname\>
292
/*! Requires the following line to be present above:
294
const QXmlStreamAttributes attrs( attributes() );
297
#define READ_ATTR_WITHOUT_NS(atrname) \
299
if (attrs.hasAttribute(STRINGIFY(atrname))) { \
300
atrname = attrs.value(STRINGIFY(atrname)).toString(); \
302
ELSE_WRONG_FORMAT_DEBUG( "READ_ATTR_WITHOUT_NS: " STRINGIFY(atrname) " not found" )
304
//! Like @ref READ_ATTR_WITHOUT_NS(atrname) but reads the attribute into the variable @a destination.
305
#define READ_ATTR_WITHOUT_NS_INTO(atrname, destination) \
306
if (attrs.hasAttribute(STRINGIFY(atrname))) { \
307
destination = attrs.value(STRINGIFY(atrname)).toString(); \
309
ELSE_WRONG_FORMAT_DEBUG( "READ_ATTR_WITHOUT_NS_INTO: " STRINGIFY(atrname) " not found" )
312
/*! Requires the following line to be present above:
314
const QXmlStreamAttributes attrs( attributes() );
317
#define TRY_READ_ATTR_QSTRING(atrname) \
318
QString atrname( attrs.value(m_defaultNamespace + atrname).toString() );
320
//! Like @ref TRY_READ_ATTR_WITHOUT_NS(atrname) but reads the attribute into the variable @a destination.
321
#define TRY_READ_ATTR_WITHOUT_NS_INTO(atrname, destination) \
322
destination = attrs.value(STRINGIFY(atrname)).toString();
324
//! reads boolean attribute "val" prefixed with default namespace, defaults to true
325
#define READ_BOOLEAN_VAL \
326
readBooleanAttr(QUALIFIED_NAME(val), true)
328
//! Converts @a string into integer @a destination; returns KoFilter::WrongFormat on failure.
329
//! @warning @a destination is left unchanged if @a string is empty, so it is up to developer to initialize it.
330
#define STRING_TO_INT(string, destination, debugElement) \
331
if (string.isEmpty()) {} else { \
333
const int val_tmp = string.toInt(&ok); \
335
kDebug() << "STRING_TO_INT: error converting" << string << "to int (attribute" << debugElement << ")"; \
336
return KoFilter::WrongFormat; \
338
destination = val_tmp; \
341
//! Converts @a string into a qreal value in @a destination; returns KoFilter::WrongFormat on failure.
342
//! @warning @a destination is left unchanged if @a string is empty, so it is up to developer to initialize it.
343
#define STRING_TO_QREAL(string, destination, debugElement) \
344
if (string.isEmpty()) {} else { \
346
const qreal val_tmp = string.toDouble(&ok); \
348
kDebug() << "STRING_TO_DOUBLE: error converting" << string << "to qreal (attribute" << debugElement << ")"; \
349
return KoFilter::WrongFormat; \
351
destination = val_tmp; \
354
//! Skips everything until end of CURRENT_EL is pulled
355
#define SKIP_EVERYTHING \
356
kDebug() << "Skipping everything in element" << qualifiedName() << "..."; \
357
const QString qn(qualifiedName().toString()); \
362
if (isEndElement() && qualifiedName() == qn) { \
368
#define SKIP_EVERYTHING_AND_RETURN \
372
#define BIND_READ_METHOD(name, method) \
373
m_readMethods.insert(QLatin1String(name), &MSOOXML_CURRENT_CLASS::read_ ## method);
375
#define BIND_READ(name) \
376
BIND_READ_METHOD(STRINGIFY(name), name)
378
#define BIND_READ_SKIP(name) \
379
BIND_READ_METHOD(STRINGIFY(name), SKIP)
381
#define BIND_READ_METHOD_HASH(hash, name, method) \
382
hash.insert(QLatin1String(name), &MSOOXML_CURRENT_CLASS::read_ ## method);
384
#define BIND_READ_HASH(hash, name) \
385
BIND_READ_METHOD_HASH(hash, STRINGIFY(name), name)
387
#define BIND_READ_HASH_SKIP(hash, name) \
388
BIND_READ_METHOD_HASH(hash, STRINGIFY(name), SKIP)