WebCore: Patch for https://bugs.webkit.org/show_bug.cgi?id=41146
[WebKit-https.git] / WebCore / dom / DatasetDOMStringMap.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "DatasetDOMStringMap.h"
28
29 #include "Attribute.h"
30 #include "Element.h"
31 #include "ExceptionCode.h"
32 #include "NamedNodeMap.h"
33 #include <wtf/ASCIICType.h>
34
35 namespace WebCore {
36
37 static bool isValidAttributeName(const String& name)
38 {
39     if (!name.startsWith("data-"))
40         return false;
41
42     const UChar* characters = name.characters();
43     unsigned length = name.length();
44     for (unsigned i = 5; i < length; ++i) {
45         if (isASCIIUpper(characters[i]))
46             return false;
47     }
48
49     return true;
50 }
51
52 static String convertAttributeNameToPropertyName(const String& name)
53 {
54     Vector<UChar> newStringBuffer;
55
56     const UChar* characters = name.characters();
57     unsigned length = name.length();
58     for (unsigned i = 5; i < length; ++i) {
59         if (characters[i] != '-')
60             newStringBuffer.append(characters[i]);
61         else {
62             if ((i + 1 < length) && isASCIILower(characters[i + 1])) {
63                 newStringBuffer.append(toASCIIUpper(characters[i + 1]));
64                 ++i;
65             } else
66                 newStringBuffer.append(characters[i]);
67         }
68     }
69
70     return String::adopt(newStringBuffer);
71 }
72
73 static bool propertyNameMatchesAttributeName(const String& propertyName, const String& attributeName)
74 {
75     // FIXME: This should be able to match without creating a new string.
76
77     if (!isValidAttributeName(attributeName))
78         return false;
79
80     String convertedName = convertAttributeNameToPropertyName(attributeName);
81     return (convertedName == propertyName);
82 }
83
84 static bool isValidPropertyName(const String& name)
85 {
86     const UChar* characters = name.characters();
87     unsigned length = name.length();
88     for (unsigned i = 0; i < length; ++i) {
89         if (characters[i] == '-' && (i + 1 < length) && isASCIILower(characters[i + 1]))
90             return false;
91     }
92     return true;
93 }
94
95 static String convertPropertyNameToAttributeName(const String& name)
96 {
97     Vector<UChar> newStringBuffer;
98
99     newStringBuffer.append('d');
100     newStringBuffer.append('a');
101     newStringBuffer.append('t');
102     newStringBuffer.append('a');
103     newStringBuffer.append('-');
104
105     const UChar* characters = name.characters();
106     unsigned length = name.length();
107     for (unsigned i = 0; i < length; ++i) {
108         if (isASCIIUpper(characters[i])) {
109             newStringBuffer.append('-');
110             newStringBuffer.append(toASCIILower(characters[i]));
111         } else
112             newStringBuffer.append(characters[i]);
113     }
114
115     return String::adopt(newStringBuffer);
116 }
117
118
119 void DatasetDOMStringMap::ref()
120 {
121     m_element->ref();
122 }
123
124 void DatasetDOMStringMap::deref()
125 {
126     m_element->deref();
127 }
128
129 void DatasetDOMStringMap::getNames(Vector<String>& names)
130 {
131     NamedNodeMap* attributeMap = m_element->attributes(true);
132     if (attributeMap) {
133         unsigned length = attributeMap->length();
134         for (unsigned i = 0; i < length; i++) {
135             Attribute* attribute = attributeMap->attributeItem(i);
136             if (isValidAttributeName(attribute->localName()))
137                 names.append(convertAttributeNameToPropertyName(attribute->localName()));
138         }
139     }
140 }
141
142 String DatasetDOMStringMap::item(const String& name)
143 {
144     NamedNodeMap* attributeMap = m_element->attributes(true);
145     if (attributeMap) {
146         unsigned length = attributeMap->length();
147         for (unsigned i = 0; i < length; i++) {
148             Attribute* attribute = attributeMap->attributeItem(i);
149             if (propertyNameMatchesAttributeName(name, attribute->localName()))
150                 return attribute->value();
151         }
152     }
153
154     return String();
155 }
156
157 bool DatasetDOMStringMap::contains(const String& name)
158 {
159     NamedNodeMap* attributeMap = m_element->attributes(true);
160     if (attributeMap) {
161         unsigned length = attributeMap->length();
162         for (unsigned i = 0; i < length; i++) {
163             Attribute* attribute = attributeMap->attributeItem(i);
164             if (propertyNameMatchesAttributeName(name, attribute->localName()))
165                 return true;
166         }
167     }
168     return false;
169 }
170
171 void DatasetDOMStringMap::setItem(const String& name, const String& value, ExceptionCode& ec)
172 {
173     if (!isValidPropertyName(name)) {
174         ec = SYNTAX_ERR;
175         return;
176     }
177
178     m_element->setAttribute(convertPropertyNameToAttributeName(name), value, ec);
179 }
180
181 void DatasetDOMStringMap::deleteItem(const String& name, ExceptionCode& ec)
182 {
183     if (!isValidPropertyName(name)) {
184         ec = SYNTAX_ERR;
185         return;
186     }
187
188     ExceptionCode dummy;
189     m_element->removeAttribute(convertPropertyNameToAttributeName(name), dummy);
190 }
191
192 } // namespace WebCore