1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 //
43 //  W A R N I N G
44 //  -------------
45 //
46 // This file is not part of the Qt API.  It exists purely as an
47 // implementation detail.  This header file may change from version to
48 // version without notice, or even be removed.
49 //
50 // We mean it.
51 
52 #ifndef Patternist_NamePool_H
53 #define Patternist_NamePool_H
54 
55 #include <QHash>
56 #include <QReadLocker>
57 #include <QReadWriteLock>
58 #include <QSharedData>
59 #include <QString>
60 #include <QVector>
61 #include <QXmlName>
62 
63 #include <QtXmlPatterns/private/qprimitives_p.h>
64 
65 QT_BEGIN_HEADER
66 
67 QT_BEGIN_NAMESPACE
68 
69 namespace QPatternist
70 {
71     /**
72      * @short Store names such as namespace bindings and QNames and allows them to
73      * be referenced in efficient ways.
74      *
75      * Once a string have been inserted it stays there and cannot be removed. The
76      * only way to deallocate any string in the NamePool is to deallocate the
77      * NamePool itself, as a whole.
78      *
79      * This class is not only reentrant, it is thread-safe in all sense of the
80      * word. All functions of this class can be called concurrently. This is
81      * achieved by internal locking.
82      *
83      * @author Frans Englich <frans.englich@nokia.com>
84      * @todo Use QSubStrings, we can save very many heap allocations by that.
85      * @todo Check limits
86      */
87     class Q_AUTOTEST_EXPORT NamePool : public QSharedData
88     {
89     public:
90         typedef QExplicitlySharedDataPointer<NamePool> Ptr;
91 
92     private:
93         friend class StandardNamespaces;
94 
95         enum
96         {
97             NoSuchValue         = -1,
98             /**
99              * This must be identical to the amount of members in
100              * StandardNamespaces.
101              */
102             StandardNamespaceCount = 11,
103             StandardPrefixCount = 9,
104             StandardLocalNameCount = 141
105         };
106 
107         QVector<QString> m_prefixes;
108         QVector<QString> m_namespaces;
109         QVector<QString> m_localNames;
110 
111         /**
112          * This hash contains no essential data, but speeds up
113          * finding a prefix in m_prefixes by mapping a prefix(the key) to
114          * the index into m_prefixes(which the value is).
115          *
116          * In other words, one can skip this variable at the cost of having
117          * to linearly loop over prefixes, in order to find the entry.
118          */
119         QHash<QString, QXmlName::PrefixCode> m_prefixMapping;
120 
121         /**
122          * Same as m_prefixMapping but applies for URIs, and hence m_namespaces instead
123          * of m_prefixes.
124          */
125         QHash<QString, QXmlName::NamespaceCode> m_namespaceMapping;
126 
127         QHash<QString, QXmlName::LocalNameCode> m_localNameMapping;
128 
129         enum DefaultCapacities
130         {
131             DefaultPrefixCapacity = 10,
132             DefaultURICapacity = DefaultPrefixCapacity,
133             /**
134              * It looks like it's quite common with 40-60 different local names per XML
135              * vocabulary. For background, see:
136              *
137              * - http://englich.wordpress.com/2007/01/11/representing-xml/
138              * - http://englich.wordpress.com/2007/01/09/xmlstat/
139              */
140             DefaultLocalNameCapacity = 60
141         };
142 
143     public:
144         NamePool();
145 
146         /**
147          * @short Allocates a namespace binding for @p prefix and @p uri.
148          *
149          * In the returned QXmlName, the local name is
150          * StandardLocalNames::empty, and QXmlName::prefix() and
151          * QXmlName::namespaceUri() returns @p prefix and @p uri, respectively.
152          *
153          * In older versions of this code, the class NamespaceBinding existed,
154          * but as part of having the public class QXmlName, it was dropped and
155          * a special interpretation/convention involving use of QXmlName was
156          * adopted.
157          */
158         QXmlName allocateBinding(const QString &prefix, const QString &uri);
159 
160         QXmlName allocateQName(const QString &uri, const QString &localName, const QString &prefix = QString());
161 
allocateQName(const QXmlName::NamespaceCode uri,const QString & ln)162         inline QXmlName allocateQName(const QXmlName::NamespaceCode uri, const QString &ln)
163         {
164             /* We don't lock here, but we do in allocateLocalName(). */
165             return QXmlName(uri, allocateLocalName(ln));
166         }
167 
stringForLocalName(const QXmlName::LocalNameCode code)168         inline const QString &stringForLocalName(const QXmlName::LocalNameCode code) const
169         {
170             const QReadLocker l(&lock);
171             return m_localNames.at(code);
172         }
173 
stringForPrefix(const QXmlName::PrefixCode code)174         inline const QString &stringForPrefix(const QXmlName::PrefixCode code) const
175         {
176             const QReadLocker l(&lock);
177             return m_prefixes.at(code);
178         }
179 
stringForNamespace(const QXmlName::NamespaceCode code)180         inline const QString &stringForNamespace(const QXmlName::NamespaceCode code) const
181         {
182             const QReadLocker l(&lock);
183             return m_namespaces.at(code);
184         }
185 
186         QString displayName(const QXmlName qName) const;
187 
toLexical(const QXmlName qName)188         inline QString toLexical(const QXmlName qName) const
189         {
190             const QReadLocker l(&lock);
191             Q_ASSERT_X(!qName.isNull(), "", "It makes no sense to call toLexical() on a null name.");
192 
193             if(qName.hasPrefix())
194             {
195                 const QString &p = m_prefixes.at(qName.prefix());
196                 return p + QLatin1Char(':') + m_localNames.at(qName.localName());
197             }
198             else
199                 return m_localNames.at(qName.localName());
200         }
201 
allocateNamespace(const QString & uri)202         inline QXmlName::NamespaceCode allocateNamespace(const QString &uri)
203         {
204             const QWriteLocker l(&lock);
205             return unlockedAllocateNamespace(uri);
206         }
207 
allocateLocalName(const QString & ln)208         inline QXmlName::LocalNameCode allocateLocalName(const QString &ln)
209         {
210             const QWriteLocker l(&lock);
211             return unlockedAllocateLocalName(ln);
212         }
213 
allocatePrefix(const QString & prefix)214         inline QXmlName::PrefixCode allocatePrefix(const QString &prefix)
215         {
216             const QWriteLocker l(&lock);
217             return unlockedAllocatePrefix(prefix);
218         }
219 
220         QString toClarkName(const QXmlName &name) const;
221         QXmlName fromClarkName(const QString &clarkName);
222 
223     private:
224         /**
225          * @note This function can not be called concurrently.
226          */
227         QXmlName::NamespaceCode unlockedAllocateNamespace(const QString &uri);
228 
229         /**
230          * @note This function can not be called concurrently.
231          */
232         QXmlName::LocalNameCode unlockedAllocateLocalName(const QString &ln);
233 
234         /**
235          * It's assumed that @p prefix is a valid @c NCName.
236          *
237          * @note This function can not be called concurrently.
238          */
239         QXmlName::PrefixCode unlockedAllocatePrefix(const QString &prefix);
240 
241         Q_DISABLE_COPY(NamePool)
242 
243         /**
244          * @note This function can not be called concurrently.
245          */
246         const QString &displayPrefix(const QXmlName::NamespaceCode nc) const;
247 
248         mutable QReadWriteLock lock;
249     };
250 
251     /**
252      * @short Formats QName.
253      *
254      * @relates QXmlName
255      */
formatKeyword(const NamePool::Ptr & np,const QXmlName name)256     static inline QString formatKeyword(const NamePool::Ptr &np, const QXmlName name)
257     {
258         return QLatin1String("<span class='XQuery-keyword'>")   +
259                escape(np->displayName(name))                    +
260                QLatin1String("</span>");
261     }
262 
263     /**
264      * @see NamespaceResolver::Constants
265      */
266     class StandardNamespaces
267     {
268     public:
269         enum ID
270         {
271             /**
272              * This does not mean empty in the sense of "empty", but
273              * in the sense of an empty string, "".
274              *
275              * Its value, zero, is significant.
276              */
277             empty = 0,
278             fn,
279             local,
280             xml,
281             xmlns,
282             xs,
283             xsi,
284             xslt,
285             /**
286              * @short A special value that when passed as the namespace part
287              * to NamespaceResolver::addBinding(), undeclares the prefix.
288              *
289              * This is used by the namespace prolog declaration.
290              *
291              * A dummy value is added to the name pool.
292              */
293             UndeclarePrefix,
294 
295             /**
296              * Signals that a node shouldn't inherit namespaces from its parent. Must be used
297              * with StandardPrefixes::StopNamespaceInheritance.
298              */
299             StopNamespaceInheritance,
300 
301             /**
302              * A namespace used to identify for instance @c \#all template
303              * mode in XSL-T.
304              */
305             InternalXSLT
306         };
307     };
308 
309     // const QString * a = &*qset.insert("foo");
310     class StandardLocalNames
311     {
312     public:
313         enum
314         {
315             abs,
316             adjust_dateTime_to_timezone,
317             adjust_date_to_timezone,
318             adjust_time_to_timezone,
319             all,
320             arity,
321             avg,
322             base,
323             base_uri,
324             boolean,
325             ceiling,
326             codepoint_equal,
327             codepoints_to_string,
328             collection,
329             compare,
330             concat,
331             contains,
332             count,
333             current,
334             current_date,
335             current_dateTime,
336             current_time,
337             data,
338             dateTime,
339             day_from_date,
340             day_from_dateTime,
341             days_from_duration,
342             deep_equal,
343             Default,
344             default_collation,
345             distinct_values,
346             doc,
347             doc_available,
348             document,
349             document_uri,
350             element_available,
351             empty,
352             encode_for_uri,
353             ends_with,
354             error,
355             escape_html_uri,
356             exactly_one,
357             exists,
358             False,
359             floor,
360             function_available,
361             function_name,
362             generate_id,
363             generic_string_join,
364             hours_from_dateTime,
365             hours_from_duration,
366             hours_from_time,
367             id,
368             idref,
369             implicit_timezone,
370             index_of,
371             in_scope_prefixes,
372             insert_before,
373             iri_to_uri,
374             is_schema_aware,
375             key,
376             lang,
377             last,
378             local_name,
379             local_name_from_QName,
380             lower_case,
381             matches,
382             max,
383             min,
384             minutes_from_dateTime,
385             minutes_from_duration,
386             minutes_from_time,
387             month_from_date,
388             month_from_dateTime,
389             months_from_duration,
390             name,
391             namespace_uri,
392             namespace_uri_for_prefix,
393             namespace_uri_from_QName,
394             nilled,
395             node_name,
396             normalize_space,
397             normalize_unicode,
398             Not,
399             number,
400             one_or_more,
401             position,
402             prefix_from_QName,
403             product_name,
404             product_version,
405             property_name,
406             QName,
407             remove,
408             replace,
409             resolve_QName,
410             resolve_uri,
411             reverse,
412             root,
413             round,
414             round_half_to_even,
415             seconds_from_dateTime,
416             seconds_from_duration,
417             seconds_from_time,
418             sourceValue,
419             starts_with,
420             static_base_uri,
421             string,
422             string_join,
423             string_length,
424             string_to_codepoints,
425             subsequence,
426             substring,
427             substring_after,
428             substring_before,
429             sum,
430             supports_backwards_compatibility,
431             supports_serialization,
432             system_property,
433             timezone_from_date,
434             timezone_from_dateTime,
435             timezone_from_time,
436             tokenize,
437             trace,
438             translate,
439             True,
440             type_available,
441             unordered,
442             unparsed_entity_public_id,
443             unparsed_entity_uri,
444             unparsed_text,
445             unparsed_text_available,
446             upper_case,
447             vendor,
448             vendor_url,
449             version,
450             xml,
451             xmlns,
452             year_from_date,
453             year_from_dateTime,
454             years_from_duration,
455             zero_or_one
456         };
457     };
458 
459     class StandardPrefixes
460     {
461     public:
462         enum
463         {
464             /**
465              * This does not mean empty in the sense of "empty", but
466              * in the sense of an empty string, "".
467              *
468              * Its value, zero, is significant.
469              */
470             empty = 0,
471             fn,
472             local,
473             xml,
474             xmlns,
475             xs,
476             xsi,
477             ns0,
478             StopNamespaceInheritance
479         };
480     };
481 }
482 
localName()483 inline QXmlName::LocalNameCode QXmlName::localName() const
484 {
485     return (m_qNameCode & LocalNameMask) >> LocalNameOffset;
486 }
487 
prefix()488 inline QXmlName::PrefixCode QXmlName::prefix() const
489 {
490     return (m_qNameCode & PrefixMask) >> PrefixOffset;
491 }
492 
hasPrefix()493 inline bool QXmlName::hasPrefix() const
494 {
495     return prefix() != 0;
496 }
497 
hasNamespace()498 inline bool QXmlName::hasNamespace() const
499 {
500     return namespaceURI() != 0;
501 }
502 
namespaceURI()503 inline QXmlName::NamespaceCode QXmlName::namespaceURI() const
504 {
505     return (m_qNameCode & NamespaceMask) >> NamespaceOffset;
506 }
507 
isLexicallyEqual(const QXmlName & other)508 inline bool QXmlName::isLexicallyEqual(const QXmlName &other) const
509 {
510     return (m_qNameCode & LexicalQNameMask) == (other.m_qNameCode & LexicalQNameMask);
511 }
512 
setPrefix(const PrefixCode c)513 inline void QXmlName::setPrefix(const PrefixCode c)
514 {
515     m_qNameCode |= (c << PrefixOffset);
516 }
517 
setNamespaceURI(const NamespaceCode c)518 inline void QXmlName::setNamespaceURI(const NamespaceCode c)
519 {
520     m_qNameCode |= (c << NamespaceOffset);
521 }
522 
setLocalName(const LocalNameCode c)523 inline void QXmlName::setLocalName(const LocalNameCode c)
524 {
525     m_qNameCode |= (c << LocalNameOffset);
526 }
527 
code()528 inline QXmlName::Code QXmlName::code() const
529 {
530     return m_qNameCode;
531 }
532 
QXmlName(const NamespaceCode uri,const LocalNameCode ln,const PrefixCode p)533 inline QXmlName::QXmlName(const NamespaceCode uri,
534                           const LocalNameCode ln,
535                           const PrefixCode p) : m_qNameCode((uri << NamespaceOffset) +
536                                                             (ln << LocalNameOffset)  +
537                                                             (p << PrefixOffset))
538 {
539     /* We can't use members like prefix() here because if one of the
540      * values are to large, they would overflow into the others. */
541     Q_ASSERT_X(p <= MaximumPrefixes, "",
542                qPrintable(QString::fromLatin1("NamePool prefix limits: max is %1, therefore %2 exceeds.").arg(MaximumPrefixes).arg(p)));
543     Q_ASSERT_X(ln <= MaximumLocalNames, "",
544                qPrintable(QString::fromLatin1("NamePool local name limits: max is %1, therefore %2 exceeds.").arg(MaximumLocalNames).arg(ln)));
545     Q_ASSERT_X(uri <= MaximumNamespaces, "",
546                qPrintable(QString::fromLatin1("NamePool namespace limits: max is %1, therefore %2 exceeds.").arg(MaximumNamespaces).arg(uri)));
547 }
548 
549 
550 Q_DECLARE_TYPEINFO(QPatternist::NamePool::Ptr, Q_MOVABLE_TYPE);
551 
552 QT_END_NAMESPACE
553 
554 QT_END_HEADER
555 
556 #endif
557