1/*
2 * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
3 * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "XPathResult.h"
29
30#include "Document.h"
31#include "XPathEvaluator.h"
32
33namespace WebCore {
34
35using namespace XPath;
36
37XPathResult::XPathResult(Document& document, const Value& value)
38 : m_value(value)
39{
40 switch (m_value.type()) {
41 case Value::BooleanValue:
42 m_resultType = BOOLEAN_TYPE;
43 return;
44 case Value::NumberValue:
45 m_resultType = NUMBER_TYPE;
46 return;
47 case Value::StringValue:
48 m_resultType = STRING_TYPE;
49 return;
50 case Value::NodeSetValue:
51 m_resultType = UNORDERED_NODE_ITERATOR_TYPE;
52 m_nodeSetPosition = 0;
53 m_nodeSet = m_value.toNodeSet();
54 m_document = &document;
55 m_domTreeVersion = document.domTreeVersion();
56 return;
57 }
58 ASSERT_NOT_REACHED();
59}
60
61XPathResult::~XPathResult() = default;
62
63ExceptionOr<void> XPathResult::convertTo(unsigned short type)
64{
65 switch (type) {
66 case ANY_TYPE:
67 break;
68 case NUMBER_TYPE:
69 m_resultType = type;
70 m_value = m_value.toNumber();
71 break;
72 case STRING_TYPE:
73 m_resultType = type;
74 m_value = m_value.toString();
75 break;
76 case BOOLEAN_TYPE:
77 m_resultType = type;
78 m_value = m_value.toBoolean();
79 break;
80 case UNORDERED_NODE_ITERATOR_TYPE:
81 case UNORDERED_NODE_SNAPSHOT_TYPE:
82 case ANY_UNORDERED_NODE_TYPE:
83 case FIRST_ORDERED_NODE_TYPE: // This is correct - singleNodeValue() will take care of ordering.
84 if (!m_value.isNodeSet())
85 return Exception { TypeError };
86 m_resultType = type;
87 break;
88 case ORDERED_NODE_ITERATOR_TYPE:
89 if (!m_value.isNodeSet())
90 return Exception { TypeError };
91 m_nodeSet.sort();
92 m_resultType = type;
93 break;
94 case ORDERED_NODE_SNAPSHOT_TYPE:
95 if (!m_value.isNodeSet())
96 return Exception { TypeError };
97 m_value.toNodeSet().sort();
98 m_resultType = type;
99 break;
100 }
101 return { };
102}
103
104unsigned short XPathResult::resultType() const
105{
106 return m_resultType;
107}
108
109ExceptionOr<double> XPathResult::numberValue() const
110{
111 if (resultType() != NUMBER_TYPE)
112 return Exception { TypeError };
113 return m_value.toNumber();
114}
115
116ExceptionOr<String> XPathResult::stringValue() const
117{
118 if (resultType() != STRING_TYPE)
119 return Exception { TypeError };
120 return m_value.toString();
121}
122
123ExceptionOr<bool> XPathResult::booleanValue() const
124{
125 if (resultType() != BOOLEAN_TYPE)
126 return Exception { TypeError };
127 return m_value.toBoolean();
128}
129
130ExceptionOr<Node*> XPathResult::singleNodeValue() const
131{
132 if (resultType() != ANY_UNORDERED_NODE_TYPE && resultType() != FIRST_ORDERED_NODE_TYPE)
133 return Exception { TypeError };
134
135 auto& nodes = m_value.toNodeSet();
136 if (resultType() == FIRST_ORDERED_NODE_TYPE)
137 return nodes.firstNode();
138 else
139 return nodes.anyNode();
140}
141
142bool XPathResult::invalidIteratorState() const
143{
144 if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE)
145 return false;
146
147 ASSERT(m_document);
148 return m_document->domTreeVersion() != m_domTreeVersion;
149}
150
151ExceptionOr<unsigned> XPathResult::snapshotLength() const
152{
153 if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE)
154 return Exception { TypeError };
155
156 return m_value.toNodeSet().size();
157}
158
159ExceptionOr<Node*> XPathResult::iterateNext()
160{
161 if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE)
162 return Exception { TypeError };
163
164 if (invalidIteratorState())
165 return Exception { InvalidStateError };
166
167 if (m_nodeSetPosition >= m_nodeSet.size())
168 return nullptr;
169
170 return m_nodeSet[m_nodeSetPosition++];
171}
172
173ExceptionOr<Node*> XPathResult::snapshotItem(unsigned index)
174{
175 if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE)
176 return Exception { TypeError };
177
178 auto& nodes = m_value.toNodeSet();
179 if (index >= nodes.size())
180 return nullptr;
181
182 return nodes[index];
183}
184
185}
186