Skip to content
Snippets Groups Projects
DOMDocumentImpl.cpp 40.4 KiB
Newer Older
            DOMDocumentType *newdoctype = (DOMDocumentType *)
                createDocumentType(srcdoctype->getNodeName(),
                srcdoctype->getPublicId(),
                srcdoctype->getSystemId());
            // Values are on NamedNodeMaps
            DOMNamedNodeMap *smap = srcdoctype->getEntities();
            DOMNamedNodeMap *tmap = newdoctype->getEntities();
            if(smap != 0) {
                for(XMLSize_t i = 0; i < smap->getLength(); i++) {
                    tmap->setNamedItem(importNode(smap->item(i), true, false));
                }
            }
            smap = srcdoctype->getNotations();
            tmap = newdoctype->getNotations();
            if (smap != 0) {
                for(XMLSize_t i = 0; i < smap->getLength(); i++) {
                    tmap->setNamedItem(importNode(smap->item(i), true, false));
                }
            }
            // NOTE: At this time, the DOM definition of DocumentType
            // doesn't cover Elements and their Attributes. domimpl's
            // extentions in that area will not be preserved, even if
            // copying from domimpl to domimpl. We could special-case
            // that here. Arguably we should. Consider. ?????
            newnode = newdoctype;
        }
        break;
    case DOMNode::DOCUMENT_FRAGMENT_NODE :
        newnode = createDocumentFragment();
        // No name, kids carry value
        break;
    case DOMNode::NOTATION_NODE :
        {
            DOMNotation *srcnotation=(DOMNotation *)source;
            DOMNotationImpl *newnotation = (DOMNotationImpl *)createNotation(source->getNodeName());
            newnotation->setPublicId(srcnotation->getPublicId());
            newnotation->setSystemId(srcnotation->getSystemId());
            // Kids carry additional value
            newnode=newnotation;
            // No name, no value
            break;
        }

    case DOMNode::DOCUMENT_NODE : // Document can't be child of Document
    default:                       // Unknown node type
        throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0);
    }

    // If deep, replicate and attach the kids.
    if (deep)
        for (DOMNode *srckid = source->getFirstChild();
             srckid != 0;
             srckid = srckid->getNextSibling())
        {
            newnode->appendChild(importNode(srckid, true, false));
        }

    if (newnode->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE
        || newnode->getNodeType() == DOMNode::ENTITY_NODE) {
        castToNodeImpl(newnode)->setReadOnly(true, true);
        errorChecking = oldErrorCheckingFlag;
    }

    if (!cloningDoc)
        fNode.callUserDataHandlers(DOMUserDataHandler::NODE_IMPORTED, source, newnode);

    return newnode;
}

// user data utility
void* DOMDocumentImpl::setUserData(DOMNodeImpl* n, const XMLCh* key, void* data, DOMUserDataHandler* handler)
{
    void* oldData = 0;
Tinny Ng's avatar
Tinny Ng committed
    DOMNodeUserDataTable* node_userDataTable = 0;

    if (!fUserDataTable) {
        // create the table on heap so that it can be cleaned in destructor
Tinny Ng's avatar
Tinny Ng committed
        fUserDataTable = new (this) RefHashTableOf<DOMNodeUserDataTable>(29, true, new HashPtr());
    }
    else {
        node_userDataTable = fUserDataTable->get((void*)n);
        DOMUserDataRecord* oldDataRecord = 0;

        if (node_userDataTable) {
            oldDataRecord = node_userDataTable->get((void*)key);

            if (oldDataRecord) {
                oldData = oldDataRecord->getKey();
                node_userDataTable->removeKey((void*)key);
            }
        }
    }

    if (data) {

Tinny Ng's avatar
Tinny Ng committed
        // create the DOMNodeUserDataTable if not exists
        // create on the heap and adopted by the hashtable which will delete it upon removal.
        if (!node_userDataTable) {
            node_userDataTable  = new RefHashTableOf<DOMUserDataRecord>(29, true);
            fUserDataTable->put(n, node_userDataTable);
        }

        // clone the key first, and create the DOMUserDataRecord
        // create on the heap and adopted by the hashtable which will delete it upon removal.
        node_userDataTable->put((void*)getPooledString(key), new DOMUserDataRecord(data, handler));
    }
    else {
        if (node_userDataTable->isEmpty())
            n->hasUserData(false);
    }

    return oldData;
}

void* DOMDocumentImpl::getUserData(const DOMNodeImpl* n, const XMLCh* key) const
{
    if (fUserDataTable) {
Tinny Ng's avatar
Tinny Ng committed
        DOMNodeUserDataTable*  node_userDataTable = fUserDataTable->get((void*)n);

        if (node_userDataTable) {
            DOMUserDataRecord* dataRecord = node_userDataTable->get((void*)key);
            if (dataRecord)
                return dataRecord->getKey();
        }
    }

    return 0;
}

void DOMDocumentImpl::callUserDataHandlers(const DOMNodeImpl* n, DOMUserDataHandler::DOMOperationType operation, const DOMNode* src, const DOMNode* dst) const
{
    if (fUserDataTable) {
Tinny Ng's avatar
Tinny Ng committed
        DOMNodeUserDataTable*  node_userDataTable = fUserDataTable->get((void*)n);

        if (node_userDataTable) {
            RefHashTableOfEnumerator<DOMUserDataRecord> userDataEnum(node_userDataTable);

            // walk through the entire node_userDataTable table
            while (userDataEnum.hasMoreElements()) {
                // get the key
                XMLCh* key = (XMLCh*) userDataEnum.nextElementKey();

                // get the DOMUserDataRecord
                DOMUserDataRecord* userDataRecord = node_userDataTable->get((void*)key);

                // get the handler
                DOMUserDataHandler* handler = userDataRecord->getValue();

                if (handler) {
                    // get the data
                    void* data = userDataRecord->getKey();
                    handler->handle(operation, key, data, src, dst);
                }
            }
        }
    }
}


void DOMDocumentImpl::transferUserData(DOMNodeImpl* n1, DOMNodeImpl* n2)
{
    if (fUserDataTable) {
        fUserDataTable->transferElement((void*)n1, (void*)n2);
        n1->hasUserData(false);
        n2->hasUserData(true);
    }
}


DOMNode* DOMDocumentImpl::renameNode(DOMNode* n, const XMLCh* namespaceURI, const XMLCh* name)
{
    if (n->getOwnerDocument() != this)
        throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0);

    switch (n->getNodeType()) {
        case ELEMENT_NODE:
            return ((DOMElementImpl*)n)->rename(namespaceURI, name);
        case ATTRIBUTE_NODE:
            return ((DOMAttrImpl*)n)->rename(namespaceURI, name);
        default:
            throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0);
    }

    return 0;
}

Tinny Ng's avatar
Tinny Ng committed
void DOMDocumentImpl::release()
{
    DOMDocument* doc = (DOMDocument*) this;

    // release the docType as well
    if (fDocType) {
        castToNodeImpl(fDocType)->isToBeReleased(true);
        fDocType->release();
    }

    // delete the document memory pool
Tinny Ng's avatar
Tinny Ng committed
    delete doc;
};

void DOMDocumentImpl::release(DOMNode* object, NodeObjectType type)
{
    if (!fRecycleNodePtr)
        fRecycleNodePtr = new RefArrayOf<DOMNodePtr> (15);

    if (!fRecycleNodePtr->operator[](type))
        fRecycleNodePtr->operator[](type) = new RefStackOf<DOMNode> (15, false);

    fRecycleNodePtr->operator[](type)->push(object);
}


void * DOMDocumentImpl::allocate(size_t amount, NodeObjectType type)
{
    if (!fRecycleNodePtr)
        return allocate(amount);

    DOMNodePtr* ptr = fRecycleNodePtr->operator[](type);
    if (!ptr || ptr->empty())
        return allocate(amount);

    return (void*) ptr->pop();

}