~carlos-mazieri/ubuntu-filemanager-app/model-using-qfilesystemwatcher

« back to all changes in this revision

Viewing changes to test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimetypeparser.cpp

  • Committer: carlos.mazieri at gmail
  • Date: 2013-05-25 17:21:13 UTC
  • Revision ID: carlos.mazieri@gmail.com-20130525172113-s8e1ajb7c4egpjw5
added QMimeType to try QIcon::fromTheme() to get icons.

added a private Clipboard handling to prevent Qcliboard not working on Nemo emulator

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/
 
5
**
 
6
** This file is part of the QtCore module of the Qt Toolkit.
 
7
**
 
8
** $QT_BEGIN_LICENSE:LGPL$
 
9
** GNU Lesser General Public License Usage
 
10
** This file may be used under the terms of the GNU Lesser General Public
 
11
** License version 2.1 as published by the Free Software Foundation and
 
12
** appearing in the file LICENSE.LGPL included in the packaging of this
 
13
** file. Please review the following information to ensure the GNU Lesser
 
14
** General Public License version 2.1 requirements will be met:
 
15
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 
16
**
 
17
** In addition, as a special exception, Nokia gives you certain additional
 
18
** rights. These rights are described in the Nokia Qt LGPL Exception
 
19
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
20
**
 
21
** GNU General Public License Usage
 
22
** Alternatively, this file may be used under the terms of the GNU General
 
23
** Public License version 3.0 as published by the Free Software Foundation
 
24
** and appearing in the file LICENSE.GPL included in the packaging of this
 
25
** file. Please review the following information to ensure the GNU General
 
26
** Public License version 3.0 requirements will be met:
 
27
** http://www.gnu.org/copyleft/gpl.html.
 
28
**
 
29
** Other Usage
 
30
** Alternatively, this file may be used in accordance with the terms and
 
31
** conditions contained in a signed written agreement between you and Nokia.
 
32
**
 
33
**
 
34
**
 
35
**
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#define QT_NO_CAST_FROM_ASCII
 
43
 
 
44
#include "qmimetypeparser_p.h"
 
45
 
 
46
#include "qmimetype_p.h"
 
47
#include "qmimemagicrulematcher_p.h"
 
48
 
 
49
#include <QtCore/QCoreApplication>
 
50
#include <QtCore/QDebug>
 
51
#include <QtCore/QDir>
 
52
#include <QtCore/QPair>
 
53
#include <QtCore/QXmlStreamReader>
 
54
#include <QtCore/QXmlStreamWriter>
 
55
#include <QtCore/QStack>
 
56
 
 
57
QT_BEGIN_NAMESPACE
 
58
 
 
59
// XML tags in MIME files
 
60
static const char mimeInfoTagC[] = "mime-info";
 
61
static const char mimeTypeTagC[] = "mime-type";
 
62
static const char mimeTypeAttributeC[] = "type";
 
63
static const char subClassTagC[] = "sub-class-of";
 
64
static const char commentTagC[] = "comment";
 
65
static const char genericIconTagC[] = "generic-icon";
 
66
static const char iconTagC[] = "icon";
 
67
static const char nameAttributeC[] = "name";
 
68
static const char globTagC[] = "glob";
 
69
static const char aliasTagC[] = "alias";
 
70
static const char patternAttributeC[] = "pattern";
 
71
static const char weightAttributeC[] = "weight";
 
72
static const char caseSensitiveAttributeC[] = "case-sensitive";
 
73
static const char localeAttributeC[] = "xml:lang";
 
74
 
 
75
static const char magicTagC[] = "magic";
 
76
static const char priorityAttributeC[] = "priority";
 
77
 
 
78
static const char matchTagC[] = "match";
 
79
static const char matchValueAttributeC[] = "value";
 
80
static const char matchTypeAttributeC[] = "type";
 
81
static const char matchOffsetAttributeC[] = "offset";
 
82
static const char matchMaskAttributeC[] = "mask";
 
83
 
 
84
/*!
 
85
    \class QMimeTypeParser
 
86
    \internal
 
87
    \brief The QMimeTypeParser class parses MIME types, and builds a MIME database hierarchy by adding to QMimeDatabasePrivate.
 
88
 
 
89
    Populates QMimeDataBase
 
90
 
 
91
    \sa QMimeDatabase, QMimeMagicRuleMatcher, MagicRule, MagicStringRule, MagicByteRule, GlobPattern
 
92
    \sa QMimeTypeParser
 
93
*/
 
94
 
 
95
/*!
 
96
    \class QMimeTypeParserBase
 
97
    \internal
 
98
    \brief The QMimeTypeParserBase class parses for a sequence of <mime-type> in a generic way.
 
99
 
 
100
    Calls abstract handler function process for QMimeType it finds.
 
101
 
 
102
    \sa QMimeDatabase, QMimeMagicRuleMatcher, MagicRule, MagicStringRule, MagicByteRule, GlobPattern
 
103
    \sa QMimeTypeParser
 
104
*/
 
105
 
 
106
/*!
 
107
    \fn virtual bool QMimeTypeParserBase::process(const QMimeType &t, QString *errorMessage) = 0;
 
108
    Overwrite to process the sequence of parsed data
 
109
*/
 
110
 
 
111
QMimeTypeParserBase::ParseState QMimeTypeParserBase::nextState(ParseState currentState, const QStringRef &startElement)
 
112
{
 
113
    switch (currentState) {
 
114
    case ParseBeginning:
 
115
        if (startElement == QLatin1String(mimeInfoTagC))
 
116
            return ParseMimeInfo;
 
117
        if (startElement == QLatin1String(mimeTypeTagC))
 
118
            return ParseMimeType;
 
119
        return ParseError;
 
120
    case ParseMimeInfo:
 
121
        return startElement == QLatin1String(mimeTypeTagC) ? ParseMimeType : ParseError;
 
122
    case ParseMimeType:
 
123
    case ParseComment:
 
124
    case ParseGenericIcon:
 
125
    case ParseIcon:
 
126
    case ParseGlobPattern:
 
127
    case ParseSubClass:
 
128
    case ParseAlias:
 
129
    case ParseOtherMimeTypeSubTag:
 
130
    case ParseMagicMatchRule:
 
131
        if (startElement == QLatin1String(mimeTypeTagC)) // Sequence of <mime-type>
 
132
            return ParseMimeType;
 
133
        if (startElement == QLatin1String(commentTagC ))
 
134
            return ParseComment;
 
135
        if (startElement == QLatin1String(genericIconTagC))
 
136
            return ParseGenericIcon;
 
137
        if (startElement == QLatin1String(iconTagC))
 
138
            return ParseIcon;
 
139
        if (startElement == QLatin1String(globTagC))
 
140
            return ParseGlobPattern;
 
141
        if (startElement == QLatin1String(subClassTagC))
 
142
            return ParseSubClass;
 
143
        if (startElement == QLatin1String(aliasTagC))
 
144
            return ParseAlias;
 
145
        if (startElement == QLatin1String(magicTagC))
 
146
            return ParseMagic;
 
147
        if (startElement == QLatin1String(matchTagC))
 
148
            return ParseMagicMatchRule;
 
149
        return ParseOtherMimeTypeSubTag;
 
150
    case ParseMagic:
 
151
        if (startElement == QLatin1String(matchTagC))
 
152
            return ParseMagicMatchRule;
 
153
        break;
 
154
    case ParseError:
 
155
        break;
 
156
    }
 
157
    return ParseError;
 
158
}
 
159
 
 
160
// Parse int number from an (attribute) string)
 
161
static bool parseNumber(const QString &n, int *target, QString *errorMessage)
 
162
{
 
163
    bool ok;
 
164
    *target = n.toInt(&ok);
 
165
    if (!ok) {
 
166
        *errorMessage = QString::fromLatin1("Not a number '%1'.").arg(n);
 
167
        return false;
 
168
    }
 
169
    return true;
 
170
}
 
171
 
 
172
// Evaluate a magic match rule like
 
173
//  <match value="must be converted with BinHex" type="string" offset="11"/>
 
174
//  <match value="0x9501" type="big16" offset="0:64"/>
 
175
static bool createMagicMatchRule(const QXmlStreamAttributes &atts,
 
176
                                 QString *errorMessage, QMimeMagicRule *&rule)
 
177
{
 
178
    const QString type = atts.value(QLatin1String(matchTypeAttributeC)).toString();
 
179
    QMimeMagicRule::Type magicType = QMimeMagicRule::type(type.toLatin1());
 
180
    if (magicType == QMimeMagicRule::Invalid) {
 
181
        qWarning("%s: match type %s is not supported.", Q_FUNC_INFO, type.toUtf8().constData());
 
182
        return true;
 
183
    }
 
184
    const QString value = atts.value(QLatin1String(matchValueAttributeC)).toString();
 
185
    if (value.isEmpty()) {
 
186
        *errorMessage = QString::fromLatin1("Empty match value detected.");
 
187
        return false;
 
188
    }
 
189
    // Parse for offset as "1" or "1:10"
 
190
    int startPos, endPos;
 
191
    const QString offsetS = atts.value(QLatin1String(matchOffsetAttributeC)).toString();
 
192
    const int colonIndex = offsetS.indexOf(QLatin1Char(':'));
 
193
    const QString startPosS = colonIndex == -1 ? offsetS : offsetS.mid(0, colonIndex);
 
194
    const QString endPosS   = colonIndex == -1 ? offsetS : offsetS.mid(colonIndex + 1);
 
195
    if (!parseNumber(startPosS, &startPos, errorMessage) || !parseNumber(endPosS, &endPos, errorMessage))
 
196
        return false;
 
197
    const QString mask = atts.value(QLatin1String(matchMaskAttributeC)).toString();
 
198
 
 
199
    rule = new QMimeMagicRule(magicType, value.toUtf8(), startPos, endPos, mask.toLatin1());
 
200
 
 
201
    return true;
 
202
}
 
203
 
 
204
bool QMimeTypeParserBase::parse(QIODevice *dev, const QString &fileName, QString *errorMessage)
 
205
{
 
206
    QMimeTypePrivate data;
 
207
    int priority = 50;
 
208
    QStack<QMimeMagicRule *> currentRules; // stack for the nesting of rules
 
209
    QList<QMimeMagicRule> rules; // toplevel rules
 
210
    QXmlStreamReader reader(dev);
 
211
    ParseState ps = ParseBeginning;
 
212
    QXmlStreamAttributes atts;
 
213
    while (!reader.atEnd()) {
 
214
        switch (reader.readNext()) {
 
215
        case QXmlStreamReader::StartElement:
 
216
            ps = nextState(ps, reader.name());
 
217
            atts = reader.attributes();
 
218
            switch (ps) {
 
219
            case ParseMimeType: { // start parsing a MIME type name
 
220
                const QString name = atts.value(QLatin1String(mimeTypeAttributeC)).toString();
 
221
                if (name.isEmpty()) {
 
222
                    reader.raiseError(QString::fromLatin1("Missing '%1'-attribute").arg(QString::fromLatin1(mimeTypeAttributeC)));
 
223
                } else {
 
224
                    data.name = name;
 
225
                }
 
226
            }
 
227
                break;
 
228
            case ParseGenericIcon:
 
229
                data.genericIconName = atts.value(QLatin1String(nameAttributeC)).toString();
 
230
                break;
 
231
            case ParseIcon:
 
232
                data.iconName = atts.value(QLatin1String(nameAttributeC)).toString();
 
233
                break;
 
234
            case ParseGlobPattern: {
 
235
                const QString pattern = atts.value(QLatin1String(patternAttributeC)).toString();
 
236
                unsigned weight = atts.value(QLatin1String(weightAttributeC)).toString().toInt();
 
237
                const bool caseSensitive = atts.value(QLatin1String(caseSensitiveAttributeC)).toString() == QLatin1String("true");
 
238
 
 
239
                if (weight == 0)
 
240
                    weight = QMimeGlobPattern::DefaultWeight;
 
241
 
 
242
                Q_ASSERT(!data.name.isEmpty());
 
243
                const QMimeGlobPattern glob(pattern, data.name, weight, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
 
244
                if (!process(glob, errorMessage))   // for actual glob matching
 
245
                    return false;
 
246
                data.addGlobPattern(pattern); // just for QMimeType::globPatterns()
 
247
            }
 
248
                break;
 
249
            case ParseSubClass: {
 
250
                const QString inheritsFrom = atts.value(QLatin1String(mimeTypeAttributeC)).toString();
 
251
                if (!inheritsFrom.isEmpty())
 
252
                    processParent(data.name, inheritsFrom);
 
253
            }
 
254
                break;
 
255
            case ParseComment: {
 
256
                // comments have locale attributes. We want the default, English one
 
257
                QString locale = atts.value(QLatin1String(localeAttributeC)).toString();
 
258
                const QString comment = reader.readElementText();
 
259
                if (locale.isEmpty())
 
260
                    locale = QString::fromLatin1("en_US");
 
261
                data.localeComments.insert(locale, comment);
 
262
            }
 
263
                break;
 
264
            case ParseAlias: {
 
265
                const QString alias = atts.value(QLatin1String(mimeTypeAttributeC)).toString();
 
266
                if (!alias.isEmpty())
 
267
                    processAlias(alias, data.name);
 
268
            }
 
269
                break;
 
270
            case ParseMagic: {
 
271
                priority = 50;
 
272
                const QString priorityS = atts.value(QLatin1String(priorityAttributeC)).toString();
 
273
                if (!priorityS.isEmpty()) {
 
274
                    if (!parseNumber(priorityS, &priority, errorMessage))
 
275
                        return false;
 
276
 
 
277
                }
 
278
                currentRules.clear();
 
279
                //qDebug() << "MAGIC start for mimetype" << data.name;
 
280
            }
 
281
                break;
 
282
            case ParseMagicMatchRule: {
 
283
                QMimeMagicRule *rule = 0;
 
284
                if (!createMagicMatchRule(atts, errorMessage, rule))
 
285
                    return false;
 
286
                QList<QMimeMagicRule> *ruleList;
 
287
                if (currentRules.isEmpty())
 
288
                    ruleList = &rules;
 
289
                else // nest this rule into the proper parent
 
290
                    ruleList = &currentRules.top()->m_subMatches;
 
291
                ruleList->append(*rule);
 
292
                //qDebug() << " MATCH added. Stack size was" << currentRules.size();
 
293
                currentRules.push(&ruleList->last());
 
294
                delete rule;
 
295
                break;
 
296
            }
 
297
            case ParseError:
 
298
                reader.raiseError(QString::fromLatin1("Unexpected element <%1>").
 
299
                                  arg(reader.name().toString()));
 
300
                break;
 
301
            default:
 
302
                break;
 
303
            }
 
304
            break;
 
305
        // continue switch QXmlStreamReader::Token...
 
306
        case QXmlStreamReader::EndElement: // Finished element
 
307
        {
 
308
            const QStringRef elementName = reader.name();
 
309
            if (elementName == QLatin1String(mimeTypeTagC)) {
 
310
                if (!process(QMimeType(data), errorMessage))
 
311
                    return false;
 
312
                data.clear();
 
313
            } else if (elementName == QLatin1String(matchTagC)) {
 
314
                // Closing a <match> tag, pop stack
 
315
                currentRules.pop();
 
316
                //qDebug() << " MATCH closed. Stack size is now" << currentRules.size();
 
317
            } else if (elementName == QLatin1String(magicTagC)) {
 
318
                //qDebug() << "MAGIC ended, we got" << rules.count() << "rules, with prio" << priority;
 
319
                // Finished a <magic> sequence
 
320
                QMimeMagicRuleMatcher ruleMatcher(data.name, priority);
 
321
                ruleMatcher.addRules(rules);
 
322
                processMagicMatcher(ruleMatcher);
 
323
                rules.clear();
 
324
            }
 
325
            break;
 
326
        }
 
327
        default:
 
328
            break;
 
329
        }
 
330
    }
 
331
 
 
332
    if (reader.hasError()) {
 
333
        if (errorMessage)
 
334
            *errorMessage = QString::fromLatin1("An error has been encountered at line %1 of %2: %3:").arg(reader.lineNumber()).arg(fileName, reader.errorString());
 
335
        return false;
 
336
    }
 
337
 
 
338
    return true;
 
339
}
 
340
 
 
341
QT_END_NAMESPACE