Avoid upconverting strings in various places in WebCore
[WebKit-https.git] / Source / 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 <wtf/ASCIICType.h>
33 #include <wtf/text/StringBuilder.h>
34
35 namespace WebCore {
36
37 static bool isValidAttributeName(const String& name)
38 {
39     if (!name.startsWith("data-"))
40         return false;
41
42     unsigned length = name.length();
43     for (unsigned i = 5; i < length; ++i) {
44         if (isASCIIUpper(name[i]))
45             return false;
46     }
47
48     return true;
49 }
50
51 static String convertAttributeNameToPropertyName(const String& name)
52 {
53     StringBuilder stringBuilder;
54
55     unsigned length = name.length();
56     for (unsigned i = 5; i < length; ++i) {
57         UChar character = name[i];
58         if (character != '-')
59             stringBuilder.append(character);
60         else {
61             if ((i + 1 < length) && isASCIILower(name[i + 1])) {
62                 stringBuilder.append(toASCIIUpper(name[i + 1]));
63                 ++i;
64             } else
65                 stringBuilder.append(character);
66         }
67     }
68
69     return stringBuilder.toString();
70 }
71
72 static bool propertyNameMatchesAttributeName(const String& propertyName, const String& attributeName)
73 {
74     if (!attributeName.startsWith("data-"))
75         return false;
76
77     unsigned propertyLength = propertyName.length();
78     unsigned attributeLength = attributeName.length();
79
80     unsigned a = 5;
81     unsigned p = 0;
82     bool wordBoundary = false;
83     while (a < attributeLength && p < propertyLength) {
84         const UChar currentAttributeNameChar = attributeName[a];
85         if (currentAttributeNameChar == '-' && a + 1 < attributeLength && attributeName[a + 1] != '-')
86             wordBoundary = true;
87         else {
88             if ((wordBoundary ? toASCIIUpper(currentAttributeNameChar) : currentAttributeNameChar) != propertyName[p])
89                 return false;
90             p++;
91             wordBoundary = false;
92         }
93         a++;
94     }
95
96     return (a == attributeLength && p == propertyLength);
97 }
98
99 static bool isValidPropertyName(const String& name)
100 {
101     unsigned length = name.length();
102     for (unsigned i = 0; i < length; ++i) {
103         if (name[i] == '-' && (i + 1 < length) && isASCIILower(name[i + 1]))
104             return false;
105     }
106     return true;
107 }
108
109 static String convertPropertyNameToAttributeName(const String& name)
110 {
111     StringBuilder builder;
112     builder.append("data-");
113
114     unsigned length = name.length();
115     for (unsigned i = 0; i < length; ++i) {
116         UChar character = name[i];
117         if (isASCIIUpper(character)) {
118             builder.append('-');
119             builder.append(toASCIILower(character));
120         } else
121             builder.append(character);
122     }
123
124     return builder.toString();
125 }
126
127 void DatasetDOMStringMap::ref()
128 {
129     m_element->ref();
130 }
131
132 void DatasetDOMStringMap::deref()
133 {
134     m_element->deref();
135 }
136
137 void DatasetDOMStringMap::getNames(Vector<String>& names)
138 {
139     if (!m_element->hasAttributes())
140         return;
141
142     unsigned length = m_element->attributeCount();
143     for (unsigned i = 0; i < length; i++) {
144         const Attribute* attribute = m_element->attributeItem(i);
145         if (isValidAttributeName(attribute->localName()))
146             names.append(convertAttributeNameToPropertyName(attribute->localName()));
147     }
148 }
149
150 String DatasetDOMStringMap::item(const String& name)
151 {
152     if (!m_element->hasAttributes())
153         return String();
154
155     unsigned length = m_element->attributeCount();
156     for (unsigned i = 0; i < length; i++) {
157         const Attribute* attribute = m_element->attributeItem(i);
158         if (propertyNameMatchesAttributeName(name, attribute->localName()))
159             return attribute->value();
160     }
161
162     return String();
163 }
164
165 bool DatasetDOMStringMap::contains(const String& name)
166 {
167     if (!m_element->hasAttributes())
168         return false;
169
170     unsigned length = m_element->attributeCount();
171     for (unsigned i = 0; i < length; i++) {
172         const Attribute* attribute = m_element->attributeItem(i);
173         if (propertyNameMatchesAttributeName(name, attribute->localName()))
174             return true;
175     }
176
177     return false;
178 }
179
180 void DatasetDOMStringMap::setItem(const String& name, const String& value, ExceptionCode& ec)
181 {
182     if (!isValidPropertyName(name)) {
183         ec = SYNTAX_ERR;
184         return;
185     }
186
187     m_element->setAttribute(convertPropertyNameToAttributeName(name), value, ec);
188 }
189
190 void DatasetDOMStringMap::deleteItem(const String& name, ExceptionCode& ec)
191 {
192     if (!isValidPropertyName(name)) {
193         ec = SYNTAX_ERR;
194         return;
195     }
196
197     m_element->removeAttribute(convertPropertyNameToAttributeName(name));
198 }
199
200 } // namespace WebCore