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