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 "Node.h"
32#include "ExceptionCode.h"
33#include "XPathEvaluator.h"
34#include "XPathException.h"
35
36namespace WebCore {
37
38using namespace XPath;
39
40XPathResult::XPathResult(Document* document, const Value& value)
41    : m_value(value)
42    , m_nodeSetPosition(0)
43    , m_domTreeVersion(0)
44{
45    switch (m_value.type()) {
46        case Value::BooleanValue:
47            m_resultType = BOOLEAN_TYPE;
48            return;
49        case Value::NumberValue:
50            m_resultType = NUMBER_TYPE;
51            return;
52        case Value::StringValue:
53            m_resultType = STRING_TYPE;
54            return;
55        case Value::NodeSetValue:
56            m_resultType = UNORDERED_NODE_ITERATOR_TYPE;
57            m_nodeSetPosition = 0;
58            m_nodeSet = m_value.toNodeSet();
59            m_document = document;
60            m_domTreeVersion = document->domTreeVersion();
61            return;
62    }
63    ASSERT_NOT_REACHED();
64}
65
66XPathResult::~XPathResult()
67{
68}
69
70void XPathResult::convertTo(unsigned short type, ExceptionCode& ec)
71{
72    switch (type) {
73        case ANY_TYPE:
74            break;
75        case NUMBER_TYPE:
76            m_resultType = type;
77            m_value = m_value.toNumber();
78            break;
79        case STRING_TYPE:
80            m_resultType = type;
81            m_value = m_value.toString();
82            break;
83        case BOOLEAN_TYPE:
84            m_resultType = type;
85            m_value = m_value.toBoolean();
86            break;
87        case UNORDERED_NODE_ITERATOR_TYPE:
88        case UNORDERED_NODE_SNAPSHOT_TYPE:
89        case ANY_UNORDERED_NODE_TYPE:
90        case FIRST_ORDERED_NODE_TYPE: // This is correct - singleNodeValue() will take care of ordering.
91            if (!m_value.isNodeSet()) {
92                ec = XPathException::TYPE_ERR;
93                return;
94            }
95            m_resultType = type;
96            break;
97        case ORDERED_NODE_ITERATOR_TYPE:
98            if (!m_value.isNodeSet()) {
99                ec = XPathException::TYPE_ERR;
100                return;
101            }
102            m_nodeSet.sort();
103            m_resultType = type;
104            break;
105        case ORDERED_NODE_SNAPSHOT_TYPE:
106            if (!m_value.isNodeSet()) {
107                ec = XPathException::TYPE_ERR;
108                return;
109            }
110            m_value.toNodeSet().sort();
111            m_resultType = type;
112            break;
113    }
114}
115
116unsigned short XPathResult::resultType() const
117{
118    return m_resultType;
119}
120
121double XPathResult::numberValue(ExceptionCode& ec) const
122{
123    if (resultType() != NUMBER_TYPE) {
124        ec = XPathException::TYPE_ERR;
125        return 0.0;
126    }
127    return m_value.toNumber();
128}
129
130String XPathResult::stringValue(ExceptionCode& ec) const
131{
132    if (resultType() != STRING_TYPE) {
133        ec = XPathException::TYPE_ERR;
134        return String();
135    }
136    return m_value.toString();
137}
138
139bool XPathResult::booleanValue(ExceptionCode& ec) const
140{
141    if (resultType() != BOOLEAN_TYPE) {
142        ec = XPathException::TYPE_ERR;
143        return false;
144    }
145    return m_value.toBoolean();
146}
147
148Node* XPathResult::singleNodeValue(ExceptionCode& ec) const
149{
150    if (resultType() != ANY_UNORDERED_NODE_TYPE && resultType() != FIRST_ORDERED_NODE_TYPE) {
151        ec = XPathException::TYPE_ERR;
152        return 0;
153    }
154
155    const NodeSet& nodes = m_value.toNodeSet();
156    if (resultType() == FIRST_ORDERED_NODE_TYPE)
157        return nodes.firstNode();
158    else
159        return nodes.anyNode();
160}
161
162bool XPathResult::invalidIteratorState() const
163{
164    if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE)
165        return false;
166
167    ASSERT(m_document);
168    return m_document->domTreeVersion() != m_domTreeVersion;
169}
170
171unsigned long XPathResult::snapshotLength(ExceptionCode& ec) const
172{
173    if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) {
174        ec = XPathException::TYPE_ERR;
175        return 0;
176    }
177
178    return m_value.toNodeSet().size();
179}
180
181Node* XPathResult::iterateNext(ExceptionCode& ec)
182{
183    if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE) {
184        ec = XPathException::TYPE_ERR;
185        return 0;
186    }
187
188    if (invalidIteratorState()) {
189        ec = INVALID_STATE_ERR;
190        return 0;
191    }
192
193    if (m_nodeSetPosition + 1 > m_nodeSet.size())
194        return 0;
195
196    Node* node = m_nodeSet[m_nodeSetPosition];
197
198    m_nodeSetPosition++;
199
200    return node;
201}
202
203Node* XPathResult::snapshotItem(unsigned long index, ExceptionCode& ec)
204{
205    if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) {
206        ec = XPathException::TYPE_ERR;
207        return 0;
208    }
209
210    const NodeSet& nodes = m_value.toNodeSet();
211    if (index >= nodes.size())
212        return 0;
213
214    return nodes[index];
215}
216
217}
218