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