• 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 "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