File indexing completed on 2024-10-13 12:12:53

0001 /*
0002  * This file is part of the DOM implementation for KDE.
0003  *
0004  * Copyright (C) 2008, 2009 Maksim Orlovich (maksim@kde.org)
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  *
0021  */
0022 
0023 #include "idstring.h"
0024 #include <assert.h>
0025 
0026 namespace khtml
0027 {
0028 
0029 CaseNormalizeMode IDTableBase::MappingKey::caseNormalizationMode;
0030 
0031 bool IDTableBase::MappingKey::operator==(const MappingKey &other) const
0032 {
0033     if (IDTableBase::MappingKey::caseNormalizationMode == IDS_CaseSensitive) {
0034         return !strcmp(str, other.str);
0035     } else {
0036         return !strcasecmp(str, other.str);
0037     }
0038 }
0039 
0040 static inline unsigned int qHash(const IDTableBase::MappingKey &key)
0041 {
0042     if (!key.str) {
0043         return 82610334; //same as empty
0044     } else if (key.caseNormalizationMode == IDS_CaseSensitive) {
0045         return key.str->hash();
0046     } else if (key.caseNormalizationMode == IDS_NormalizeLower) {
0047         return key.str->lowerHash();
0048     } else { // caseNormalizationMode == IDS_NormalizeUpper
0049         return key.str->upperHash();
0050     }
0051 }
0052 
0053 void IDTableBase::releaseId(unsigned id)
0054 {
0055     IDTableBase::MappingKey::caseNormalizationMode = IDS_CaseSensitive;
0056 
0057     m_mappingLookup.remove(m_mappings[id].name);
0058     m_mappings[id].name->deref();
0059     m_idFreeList.append(id);
0060 }
0061 
0062 unsigned short IDTableBase::grabId(DOMStringImpl *origName, CaseNormalizeMode cnm)
0063 {
0064     unsigned short newId;
0065 
0066     // Check for existing one, ignoring case if needed
0067     IDTableBase::MappingKey::caseNormalizationMode = cnm;
0068     QHash<MappingKey, unsigned short>::const_iterator i = m_mappingLookup.constFind(origName);
0069     if (i != m_mappingLookup.constEnd()) {
0070         newId = *i;
0071         refId(newId);
0072         return newId;
0073     }
0074 
0075     // Nope. Allocate new ID. If there is normalization going on, we may now have to
0076     // update our case so the canonical mapping is of the expected case. We
0077     // may also have to deep-copy
0078     DOMStringImpl *name = nullptr;
0079     switch (cnm) {
0080     case IDS_CaseSensitive:
0081         if (origName->m_shallowCopy) {
0082             // Create a new copy of the data since we may be extending its
0083             // lifetime indefinitely
0084             name = new DOMStringImpl(origName->s, origName->l);
0085             name->m_hash = origName->m_hash;
0086         } else {
0087             name = origName;
0088         }
0089         break;
0090     case IDS_NormalizeUpper:
0091         name = origName->upper();
0092         break;
0093     case IDS_NormalizeLower:
0094         name = origName->lower();
0095         break;
0096     }
0097 
0098     Q_ASSERT(name);
0099     name->ref();
0100 
0101     if (!m_idFreeList.isEmpty()) {
0102         // Grab from freelist..
0103         newId = m_idFreeList.last();
0104         m_idFreeList.removeLast();
0105         m_mappings[newId].name = name;
0106     } else {
0107         // Make a new one --- if we can (we keep one spot for "last resort" mapping)
0108         if (m_mappings.size() < 0xFFFE) {
0109             m_mappings.append(Mapping(name));
0110             newId = m_mappings.size() - 1;
0111         } else {
0112             // We ran out of resources. Did we add a fallback mapping yet?
0113             // We use the same one for everything; and don't even keep track
0114             // of what it may go to, as we will have no way of freeing
0115             // the aliases. In particular, this means we no longer need the name..
0116             name->deref();
0117 
0118             if (m_mappings.size() == 0xFFFE) {
0119                 // Need a new mapping..
0120                 name = new DOMStringImpl("_khtml_fallback");
0121                 m_mappings.append(Mapping(name));
0122                 m_mappings[0xFFFF].refCount = 1; // pin it.
0123                 name->ref();
0124             } else {
0125                 name = m_mappings[0xFFFF].name; // No need to ref the name
0126                 // here as the entry is eternal anyway
0127             }
0128             newId = 0xFFFF;
0129         }
0130     }
0131 
0132     m_mappingLookup[name] = newId;
0133 
0134     refId(newId);
0135     return newId;
0136 }
0137 
0138 void IDTableBase::addStaticMapping(unsigned id, const DOMString &name)
0139 {
0140     addHiddenMapping(id, name);
0141     IDTableBase::MappingKey::caseNormalizationMode = IDS_CaseSensitive;
0142     m_mappingLookup[name.implementation()] = id;
0143 }
0144 
0145 void IDTableBase::addHiddenMapping(unsigned id, const DOMString &name)
0146 {
0147     DOMStringImpl *nameImpl = name.implementation();
0148     if (nameImpl) {
0149         nameImpl->ref();
0150     }
0151 
0152     if (id >= m_mappings.size()) {
0153         m_mappings.resize(id + 1);
0154     }
0155     m_mappings[id] = Mapping(nameImpl);
0156     m_mappings[id].refCount = 1; // Pin it.
0157 }
0158 
0159 }
0160