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