Home | History | Annotate | Download | only in dom
      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 
     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     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 
     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 
    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 
    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 
    136 void DatasetDOMStringMap::ref()
    137 {
    138     m_element->ref();
    139 }
    140 
    141 void DatasetDOMStringMap::deref()
    142 {
    143     m_element->deref();
    144 }
    145 
    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 
    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 
    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 
    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 
    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