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