|  |  | 
|  |  | 
|  |  */ | 
|  | /* | 
|  |  * Licensed to the Apache Software Foundation (ASF) under one or more | 
|  |  * contributor license agreements.  See the NOTICE file distributed with | 
|  |  * this work for additional information regarding copyright ownership. | 
|  |  * The ASF licenses this file to You under the Apache License, Version 2.0 | 
|  |  * (the "License"); you may not use this file except in compliance with | 
|  |  * the License.  You may obtain a copy of the License at | 
|  |  * | 
|  |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  |  * | 
|  |  * Unless required by applicable law or agreed to in writing, software | 
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  |  * See the License for the specific language governing permissions and | 
|  |  * limitations under the License. | 
|  |  */ | 
|  |  | 
|  | package com.sun.org.apache.xerces.internal.dom; | 
|  |  | 
|  | import java.io.Serializable; | 
|  | import java.io.IOException; | 
|  | import java.io.ObjectInputStream; | 
|  | import java.io.ObjectOutputStream; | 
|  |  | 
|  | import org.w3c.dom.DOMException; | 
|  | import org.w3c.dom.Document; | 
|  | import org.w3c.dom.Node; | 
|  | import org.w3c.dom.NodeList; | 
|  | import org.w3c.dom.UserDataHandler; | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  */ | 
|  | public abstract class ParentNode | 
|  |     extends ChildNode { | 
|  |  | 
|  |      | 
|  |     static final long serialVersionUID = 2815829867152120872L; | 
|  |  | 
|  |      | 
|  |     protected CoreDocumentImpl ownerDocument; | 
|  |  | 
|  |      | 
|  |     protected ChildNode firstChild = null; | 
|  |  | 
|  |     // transients | 
|  |  | 
|  |      | 
|  |     protected transient NodeListCache fNodeListCache = null; | 
|  |  | 
|  |     // | 
|  |     // Constructors | 
|  |     // | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     protected ParentNode(CoreDocumentImpl ownerDocument) { | 
|  |         super(ownerDocument); | 
|  |         this.ownerDocument = ownerDocument; | 
|  |     } | 
|  |  | 
|  |      | 
|  |     public ParentNode() {} | 
|  |  | 
|  |     // | 
|  |     // NodeList methods | 
|  |     // | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public Node cloneNode(boolean deep) { | 
|  |  | 
|  |         if (needsSyncChildren()) { | 
|  |             synchronizeChildren(); | 
|  |         } | 
|  |         ParentNode newnode = (ParentNode) super.cloneNode(deep); | 
|  |  | 
|  |          | 
|  |         newnode.ownerDocument = ownerDocument; | 
|  |  | 
|  |          | 
|  |         newnode.firstChild      = null; | 
|  |  | 
|  |          | 
|  |         newnode.fNodeListCache = null; | 
|  |  | 
|  |          | 
|  |         if (deep) { | 
|  |             for (ChildNode child = firstChild; | 
|  |                  child != null; | 
|  |                  child = child.nextSibling) { | 
|  |                 newnode.appendChild(child.cloneNode(true)); | 
|  |             } | 
|  |         } | 
|  |  | 
|  |         return newnode; | 
|  |  | 
|  |     } // cloneNode(boolean):Node | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public Document getOwnerDocument() { | 
|  |         return ownerDocument; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     CoreDocumentImpl ownerDocument() { | 
|  |         return ownerDocument; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     protected void setOwnerDocument(CoreDocumentImpl doc) { | 
|  |         if (needsSyncChildren()) { | 
|  |             synchronizeChildren(); | 
|  |         } | 
|  |         super.setOwnerDocument(doc); | 
|  |         ownerDocument = doc; | 
|  |         for (ChildNode child = firstChild; | 
|  |         child != null; child = child.nextSibling) { | 
|  |             child.setOwnerDocument(doc); | 
|  |         } | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public boolean hasChildNodes() { | 
|  |         if (needsSyncChildren()) { | 
|  |             synchronizeChildren(); | 
|  |         } | 
|  |         return firstChild != null; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public NodeList getChildNodes() { | 
|  |  | 
|  |         if (needsSyncChildren()) { | 
|  |             synchronizeChildren(); | 
|  |         } | 
|  |         return this; | 
|  |  | 
|  |     } // getChildNodes():NodeList | 
|  |  | 
|  |      | 
|  |     public Node getFirstChild() { | 
|  |  | 
|  |         if (needsSyncChildren()) { | 
|  |             synchronizeChildren(); | 
|  |         } | 
|  |         return firstChild; | 
|  |  | 
|  |     }   // getFirstChild():Node | 
|  |  | 
|  |      | 
|  |     public Node getLastChild() { | 
|  |  | 
|  |         if (needsSyncChildren()) { | 
|  |             synchronizeChildren(); | 
|  |         } | 
|  |         return lastChild(); | 
|  |  | 
|  |     } // getLastChild():Node | 
|  |  | 
|  |     final ChildNode lastChild() { | 
|  |          | 
|  |         return firstChild != null ? firstChild.previousSibling : null; | 
|  |     } | 
|  |  | 
|  |     final void lastChild(ChildNode node) { | 
|  |          | 
|  |         if (firstChild != null) { | 
|  |             firstChild.previousSibling = node; | 
|  |         } | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public Node insertBefore(Node newChild, Node refChild) | 
|  |         throws DOMException { | 
|  |          | 
|  |         return internalInsertBefore(newChild, refChild, false); | 
|  |     } // insertBefore(Node,Node):Node | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     Node internalInsertBefore(Node newChild, Node refChild, boolean replace) | 
|  |         throws DOMException { | 
|  |  | 
|  |         boolean errorChecking = ownerDocument.errorChecking; | 
|  |  | 
|  |         if (newChild.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { | 
|  |             // SLOW BUT SAFE: We could insert the whole subtree without | 
|  |             // juggling so many next/previous pointers. (Wipe out the | 
|  |             // parent's child-list, patch the parent pointers, set the | 
|  |             // ends of the list.) But we know some subclasses have special- | 
|  |             // case behavior they add to insertBefore(), so we don't risk it. | 
|  |             // This approch also takes fewer bytecodes. | 
|  |  | 
|  |             // NOTE: If one of the children is not a legal child of this | 
|  |             // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children | 
|  |             // have been transferred. (Alternative behaviors would be to | 
|  |             // reparent up to the first failure point or reparent all those | 
|  |             // which are acceptable to the target node, neither of which is | 
|  |             // as robust. PR-DOM-0818 isn't entirely clear on which it | 
|  |             // recommends????? | 
|  |  | 
|  |             // No need to check kids for right-document; if they weren't, | 
|  |              | 
|  |             if (errorChecking) { | 
|  |                 for (Node kid = newChild.getFirstChild();  | 
|  |                      kid != null; kid = kid.getNextSibling()) { | 
|  |  | 
|  |                     if (!ownerDocument.isKidOK(this, kid)) { | 
|  |                         throw new DOMException( | 
|  |                               DOMException.HIERARCHY_REQUEST_ERR, | 
|  |                               DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null)); | 
|  |                     } | 
|  |                 } | 
|  |             } | 
|  |  | 
|  |             while (newChild.hasChildNodes()) { | 
|  |                 insertBefore(newChild.getFirstChild(), refChild); | 
|  |             } | 
|  |             return newChild; | 
|  |         } | 
|  |  | 
|  |         if (newChild == refChild) { | 
|  |              | 
|  |             refChild = refChild.getNextSibling(); | 
|  |             removeChild(newChild); | 
|  |             insertBefore(newChild, refChild); | 
|  |             return newChild; | 
|  |         } | 
|  |  | 
|  |         if (needsSyncChildren()) { | 
|  |             synchronizeChildren(); | 
|  |         } | 
|  |  | 
|  |         if (errorChecking) { | 
|  |             if (isReadOnly()) { | 
|  |                 throw new DOMException( | 
|  |                               DOMException.NO_MODIFICATION_ALLOWED_ERR, | 
|  |                               DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null)); | 
|  |             } | 
|  |             if (newChild.getOwnerDocument() != ownerDocument && newChild != ownerDocument) { | 
|  |                 throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, | 
|  |                             DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null)); | 
|  |             } | 
|  |             if (!ownerDocument.isKidOK(this, newChild)) { | 
|  |                 throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, | 
|  |                             DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null)); | 
|  |             } | 
|  |              | 
|  |             if (refChild != null && refChild.getParentNode() != this) { | 
|  |                 throw new DOMException(DOMException.NOT_FOUND_ERR, | 
|  |                             DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null)); | 
|  |             } | 
|  |  | 
|  |             // Prevent cycles in the tree | 
|  |             // newChild cannot be ancestor of this Node, | 
|  |              | 
|  |             boolean treeSafe = true; | 
|  |             for (NodeImpl a = this; treeSafe && a != null; a = a.parentNode()) | 
|  |             { | 
|  |                 treeSafe = newChild != a; | 
|  |             } | 
|  |             if(!treeSafe) { | 
|  |                 throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, | 
|  |                             DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null)); | 
|  |             } | 
|  |         } | 
|  |  | 
|  |          | 
|  |         ownerDocument.insertingNode(this, replace); | 
|  |  | 
|  |          | 
|  |         ChildNode newInternal = (ChildNode)newChild; | 
|  |  | 
|  |         Node oldparent = newInternal.parentNode(); | 
|  |         if (oldparent != null) { | 
|  |             oldparent.removeChild(newInternal); | 
|  |         } | 
|  |  | 
|  |          | 
|  |         ChildNode refInternal = (ChildNode)refChild; | 
|  |  | 
|  |          | 
|  |         newInternal.ownerNode = this; | 
|  |         newInternal.isOwned(true); | 
|  |  | 
|  |         // Attach before and after | 
|  |          | 
|  |         if (firstChild == null) { | 
|  |              | 
|  |             firstChild = newInternal; | 
|  |             newInternal.isFirstChild(true); | 
|  |             newInternal.previousSibling = newInternal; | 
|  |         } | 
|  |         else { | 
|  |             if (refInternal == null) { | 
|  |                  | 
|  |                 ChildNode lastChild = firstChild.previousSibling; | 
|  |                 lastChild.nextSibling = newInternal; | 
|  |                 newInternal.previousSibling = lastChild; | 
|  |                 firstChild.previousSibling = newInternal; | 
|  |             } | 
|  |             else { | 
|  |                  | 
|  |                 if (refChild == firstChild) { | 
|  |                      | 
|  |                     firstChild.isFirstChild(false); | 
|  |                     newInternal.nextSibling = firstChild; | 
|  |                     newInternal.previousSibling = firstChild.previousSibling; | 
|  |                     firstChild.previousSibling = newInternal; | 
|  |                     firstChild = newInternal; | 
|  |                     newInternal.isFirstChild(true); | 
|  |                 } | 
|  |                 else { | 
|  |                      | 
|  |                     ChildNode prev = refInternal.previousSibling; | 
|  |                     newInternal.nextSibling = refInternal; | 
|  |                     prev.nextSibling = newInternal; | 
|  |                     refInternal.previousSibling = newInternal; | 
|  |                     newInternal.previousSibling = prev; | 
|  |                 } | 
|  |             } | 
|  |         } | 
|  |  | 
|  |         changed(); | 
|  |  | 
|  |          | 
|  |         if (fNodeListCache != null) { | 
|  |             if (fNodeListCache.fLength != -1) { | 
|  |                 fNodeListCache.fLength++; | 
|  |             } | 
|  |             if (fNodeListCache.fChildIndex != -1) { | 
|  |                 // if we happen to insert just before the cached node, update | 
|  |                  | 
|  |                 if (fNodeListCache.fChild == refInternal) { | 
|  |                     fNodeListCache.fChild = newInternal; | 
|  |                 } else { | 
|  |                      | 
|  |                     fNodeListCache.fChildIndex = -1; | 
|  |                 } | 
|  |             } | 
|  |         } | 
|  |  | 
|  |          | 
|  |         ownerDocument.insertedNode(this, newInternal, replace); | 
|  |  | 
|  |         checkNormalizationAfterInsert(newInternal); | 
|  |  | 
|  |         return newChild; | 
|  |  | 
|  |     } // internalInsertBefore(Node,Node,boolean):Node | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public Node removeChild(Node oldChild) | 
|  |         throws DOMException { | 
|  |          | 
|  |         return internalRemoveChild(oldChild, false); | 
|  |     } // removeChild(Node) :Node | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     Node internalRemoveChild(Node oldChild, boolean replace) | 
|  |         throws DOMException { | 
|  |  | 
|  |         CoreDocumentImpl ownerDocument = ownerDocument(); | 
|  |         if (ownerDocument.errorChecking) { | 
|  |             if (isReadOnly()) { | 
|  |                 throw new DOMException( | 
|  |                             DOMException.NO_MODIFICATION_ALLOWED_ERR, | 
|  |                             DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null)); | 
|  |             } | 
|  |             if (oldChild != null && oldChild.getParentNode() != this) { | 
|  |                 throw new DOMException(DOMException.NOT_FOUND_ERR, | 
|  |                             DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null)); | 
|  |             } | 
|  |         } | 
|  |  | 
|  |         ChildNode oldInternal = (ChildNode) oldChild; | 
|  |  | 
|  |          | 
|  |         ownerDocument.removingNode(this, oldInternal, replace); | 
|  |  | 
|  |          | 
|  |         final ChildNode oldPreviousSibling = oldInternal.previousSibling(); | 
|  |  | 
|  |          | 
|  |         if (fNodeListCache != null) { | 
|  |             if (fNodeListCache.fLength != -1) { | 
|  |                 fNodeListCache.fLength--; | 
|  |             } | 
|  |             if (fNodeListCache.fChildIndex != -1) { | 
|  |                 // if the removed node is the cached node | 
|  |                  | 
|  |                 if (fNodeListCache.fChild == oldInternal) { | 
|  |                     fNodeListCache.fChildIndex--; | 
|  |                     fNodeListCache.fChild = oldPreviousSibling; | 
|  |                 } else { | 
|  |                      | 
|  |                     fNodeListCache.fChildIndex = -1; | 
|  |                 } | 
|  |             } | 
|  |         } | 
|  |  | 
|  |         // Patch linked list around oldChild | 
|  |          | 
|  |         if (oldInternal == firstChild) { | 
|  |              | 
|  |             oldInternal.isFirstChild(false); | 
|  |             firstChild = oldInternal.nextSibling; | 
|  |             if (firstChild != null) { | 
|  |                 firstChild.isFirstChild(true); | 
|  |                 firstChild.previousSibling = oldInternal.previousSibling; | 
|  |             } | 
|  |         } else { | 
|  |             ChildNode prev = oldInternal.previousSibling; | 
|  |             ChildNode next = oldInternal.nextSibling; | 
|  |             prev.nextSibling = next; | 
|  |             if (next == null) { | 
|  |                  | 
|  |                 firstChild.previousSibling = prev; | 
|  |             } else { | 
|  |                  | 
|  |                 next.previousSibling = prev; | 
|  |             } | 
|  |         } | 
|  |  | 
|  |          | 
|  |         oldInternal.ownerNode       = ownerDocument; | 
|  |         oldInternal.isOwned(false); | 
|  |         oldInternal.nextSibling     = null; | 
|  |         oldInternal.previousSibling = null; | 
|  |  | 
|  |         changed(); | 
|  |  | 
|  |          | 
|  |         ownerDocument.removedNode(this, replace); | 
|  |  | 
|  |         checkNormalizationAfterRemove(oldPreviousSibling); | 
|  |  | 
|  |         return oldInternal; | 
|  |  | 
|  |     } // internalRemoveChild(Node,boolean):Node | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public Node replaceChild(Node newChild, Node oldChild) | 
|  |         throws DOMException { | 
|  |         // If Mutation Events are being generated, this operation might | 
|  |         // throw aggregate events twice when modifying an Attr -- once | 
|  |         // on insertion and once on removal. DOM Level 2 does not specify | 
|  |         // this as either desirable or undesirable, but hints that | 
|  |         // aggregations should be issued only once per user request. | 
|  |  | 
|  |          | 
|  |         ownerDocument.replacingNode(this); | 
|  |  | 
|  |         internalInsertBefore(newChild, oldChild, true); | 
|  |         if (newChild != oldChild) { | 
|  |             internalRemoveChild(oldChild, true); | 
|  |         } | 
|  |  | 
|  |          | 
|  |         ownerDocument.replacedNode(this); | 
|  |  | 
|  |         return oldChild; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public String getTextContent() throws DOMException { | 
|  |         Node child = getFirstChild(); | 
|  |         if (child != null) { | 
|  |             Node next = child.getNextSibling(); | 
|  |             if (next == null) { | 
|  |                 return hasTextContent(child) ? ((NodeImpl) child).getTextContent() : ""; | 
|  |             } | 
|  |             StringBuilder buf = new StringBuilder(); | 
|  |             getTextContent(buf); | 
|  |             return buf.toString(); | 
|  |         } | 
|  |         return ""; | 
|  |     } | 
|  |  | 
|  |      | 
|  |     void getTextContent(StringBuilder buf) throws DOMException { | 
|  |         Node child = getFirstChild(); | 
|  |         while (child != null) { | 
|  |             if (hasTextContent(child)) { | 
|  |                 ((NodeImpl) child).getTextContent(buf); | 
|  |             } | 
|  |             child = child.getNextSibling(); | 
|  |         } | 
|  |     } | 
|  |  | 
|  |      | 
|  |     final boolean hasTextContent(Node child) { | 
|  |         return child.getNodeType() != Node.COMMENT_NODE && | 
|  |             child.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE && | 
|  |             (child.getNodeType() != Node.TEXT_NODE || | 
|  |              ((TextImpl) child).isIgnorableWhitespace() == false); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public void setTextContent(String textContent) | 
|  |         throws DOMException { | 
|  |          | 
|  |         Node child; | 
|  |         while ((child = getFirstChild()) != null) { | 
|  |             removeChild(child); | 
|  |         } | 
|  |          | 
|  |         if (textContent != null && textContent.length() != 0){ | 
|  |             appendChild(ownerDocument().createTextNode(textContent)); | 
|  |         } | 
|  |     } | 
|  |  | 
|  |     // | 
|  |     // NodeList methods | 
|  |     // | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     private int nodeListGetLength() { | 
|  |  | 
|  |         if (fNodeListCache == null) { | 
|  |             if (needsSyncChildren()) { | 
|  |                 synchronizeChildren(); | 
|  |             } | 
|  |              | 
|  |             if (firstChild == null) { | 
|  |                 return 0; | 
|  |             } | 
|  |             if (firstChild == lastChild()) { | 
|  |                 return 1; | 
|  |             } | 
|  |              | 
|  |             fNodeListCache = ownerDocument.getNodeListCache(this); | 
|  |         } | 
|  |         if (fNodeListCache.fLength == -1) {  | 
|  |             int l; | 
|  |             ChildNode n; | 
|  |              | 
|  |             if (fNodeListCache.fChildIndex != -1 && | 
|  |                 fNodeListCache.fChild != null) { | 
|  |                 l = fNodeListCache.fChildIndex; | 
|  |                 n = fNodeListCache.fChild; | 
|  |             } else { | 
|  |                 n = firstChild; | 
|  |                 l = 0; | 
|  |             } | 
|  |             while (n != null) { | 
|  |                 l++; | 
|  |                 n = n.nextSibling; | 
|  |             } | 
|  |             fNodeListCache.fLength = l; | 
|  |         } | 
|  |  | 
|  |         return fNodeListCache.fLength; | 
|  |  | 
|  |     } // nodeListGetLength():int | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public int getLength() { | 
|  |         return nodeListGetLength(); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     private Node nodeListItem(int index) { | 
|  |  | 
|  |         if (fNodeListCache == null) { | 
|  |             if (needsSyncChildren()) { | 
|  |                 synchronizeChildren(); | 
|  |             } | 
|  |              | 
|  |             if (firstChild == lastChild()) { | 
|  |                 return index == 0 ? firstChild : null; | 
|  |             } | 
|  |              | 
|  |             fNodeListCache = ownerDocument.getNodeListCache(this); | 
|  |         } | 
|  |         int i = fNodeListCache.fChildIndex; | 
|  |         ChildNode n = fNodeListCache.fChild; | 
|  |         boolean firstAccess = true; | 
|  |          | 
|  |         if (i != -1 && n != null) { | 
|  |             firstAccess = false; | 
|  |             if (i < index) { | 
|  |                 while (i < index && n != null) { | 
|  |                     i++; | 
|  |                     n = n.nextSibling; | 
|  |                 } | 
|  |             } | 
|  |             else if (i > index) { | 
|  |                 while (i > index && n != null) { | 
|  |                     i--; | 
|  |                     n = n.previousSibling(); | 
|  |                 } | 
|  |             } | 
|  |         } | 
|  |         else { | 
|  |              | 
|  |             if (index < 0) { | 
|  |                 return null; | 
|  |             } | 
|  |             n = firstChild; | 
|  |             for (i = 0; i < index && n != null; i++) { | 
|  |                 n = n.nextSibling; | 
|  |             } | 
|  |         } | 
|  |  | 
|  |          | 
|  |         if (!firstAccess && (n == firstChild || n == lastChild())) { | 
|  |             fNodeListCache.fChildIndex = -1; | 
|  |             fNodeListCache.fChild = null; | 
|  |             ownerDocument.freeNodeListCache(fNodeListCache); | 
|  |             // we can keep using the cache until it is actually reused | 
|  |             // fNodeListCache will be nulled by the pool (document) if that | 
|  |             // happens. | 
|  |             // fNodeListCache = null; | 
|  |         } | 
|  |         else { | 
|  |              | 
|  |             fNodeListCache.fChildIndex = i; | 
|  |             fNodeListCache.fChild = n; | 
|  |         } | 
|  |         return n; | 
|  |  | 
|  |     } // nodeListItem(int):Node | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public Node item(int index) { | 
|  |         return nodeListItem(index); | 
|  |     } // item(int):Node | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     protected final NodeList getChildNodesUnoptimized() { | 
|  |         if (needsSyncChildren()) { | 
|  |             synchronizeChildren(); | 
|  |         } | 
|  |         return new NodeList() { | 
|  |                  | 
|  |  | 
|  |                  */ | 
|  |                 public int getLength() { | 
|  |                     return nodeListGetLength(); | 
|  |                 } // getLength():int | 
|  |  | 
|  |                  | 
|  |  | 
|  |                  */ | 
|  |                 public Node item(int index) { | 
|  |                     return nodeListItem(index); | 
|  |                 } // item(int):Node | 
|  |             }; | 
|  |     } // getChildNodesUnoptimized():NodeList | 
|  |  | 
|  |     // | 
|  |     // DOM2: methods, getters, setters | 
|  |     // | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public void normalize() { | 
|  |          | 
|  |         if (isNormalized()) { | 
|  |             return; | 
|  |         } | 
|  |         if (needsSyncChildren()) { | 
|  |             synchronizeChildren(); | 
|  |         } | 
|  |         ChildNode kid; | 
|  |         for (kid = firstChild; kid != null; kid = kid.nextSibling) { | 
|  |             kid.normalize(); | 
|  |         } | 
|  |         isNormalized(true); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public boolean isEqualNode(Node arg) { | 
|  |         if (!super.isEqualNode(arg)) { | 
|  |             return false; | 
|  |         } | 
|  |         // there are many ways to do this test, and there isn't any way | 
|  |         // better than another. Performance may vary greatly depending on | 
|  |          | 
|  |         Node child1 = getFirstChild(); | 
|  |         Node child2 = arg.getFirstChild(); | 
|  |         while (child1 != null && child2 != null) { | 
|  |             if (!child1.isEqualNode(child2)) { | 
|  |                 return false; | 
|  |             } | 
|  |             child1 = child1.getNextSibling(); | 
|  |             child2 = child2.getNextSibling(); | 
|  |         } | 
|  |         if (child1 != child2) { | 
|  |             return false; | 
|  |         } | 
|  |         return true; | 
|  |     } | 
|  |  | 
|  |     // | 
|  |     // Public methods | 
|  |     // | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public void setReadOnly(boolean readOnly, boolean deep) { | 
|  |  | 
|  |         super.setReadOnly(readOnly, deep); | 
|  |  | 
|  |         if (deep) { | 
|  |  | 
|  |             if (needsSyncChildren()) { | 
|  |                 synchronizeChildren(); | 
|  |             } | 
|  |  | 
|  |              | 
|  |             for (ChildNode mykid = firstChild; | 
|  |                  mykid != null; | 
|  |                  mykid = mykid.nextSibling) { | 
|  |                 if (mykid.getNodeType() != Node.ENTITY_REFERENCE_NODE) { | 
|  |                     mykid.setReadOnly(readOnly,true); | 
|  |                 } | 
|  |             } | 
|  |         } | 
|  |     } // setReadOnly(boolean,boolean) | 
|  |  | 
|  |     // | 
|  |     // Protected methods | 
|  |     // | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     protected void synchronizeChildren() { | 
|  |          | 
|  |         needsSyncChildren(false); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     void checkNormalizationAfterInsert(ChildNode insertedChild) { | 
|  |          | 
|  |         if (insertedChild.getNodeType() == Node.TEXT_NODE) { | 
|  |             ChildNode prev = insertedChild.previousSibling(); | 
|  |             ChildNode next = insertedChild.nextSibling; | 
|  |             // If an adjacent sibling of the new child is a text node, | 
|  |              | 
|  |             if ((prev != null && prev.getNodeType() == Node.TEXT_NODE) || | 
|  |                 (next != null && next.getNodeType() == Node.TEXT_NODE)) { | 
|  |                 isNormalized(false); | 
|  |             } | 
|  |         } | 
|  |         else { | 
|  |             // If the new child is not normalized, | 
|  |              | 
|  |             if (!insertedChild.isNormalized()) { | 
|  |                 isNormalized(false); | 
|  |             } | 
|  |         } | 
|  |     } // checkNormalizationAfterInsert(ChildNode) | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     void checkNormalizationAfterRemove(ChildNode previousSibling) { | 
|  |         // See if removal caused this node to be unnormalized. | 
|  |         // If the adjacent siblings of the removed child were both text nodes, | 
|  |          | 
|  |         if (previousSibling != null && | 
|  |             previousSibling.getNodeType() == Node.TEXT_NODE) { | 
|  |  | 
|  |             ChildNode next = previousSibling.nextSibling; | 
|  |             if (next != null && next.getNodeType() == Node.TEXT_NODE) { | 
|  |                 isNormalized(false); | 
|  |             } | 
|  |         } | 
|  |     } // checkNormalizationAfterRemove(Node) | 
|  |  | 
|  |     // | 
|  |     // Serialization methods | 
|  |     // | 
|  |  | 
|  |      | 
|  |     private void writeObject(ObjectOutputStream out) throws IOException { | 
|  |  | 
|  |          | 
|  |         if (needsSyncChildren()) { | 
|  |             synchronizeChildren(); | 
|  |         } | 
|  |          | 
|  |         out.defaultWriteObject(); | 
|  |  | 
|  |     } // writeObject(ObjectOutputStream) | 
|  |  | 
|  |      | 
|  |     private void readObject(ObjectInputStream ois) | 
|  |         throws ClassNotFoundException, IOException { | 
|  |  | 
|  |          | 
|  |         ois.defaultReadObject(); | 
|  |  | 
|  |         // hardset synchildren - so we don't try to sync - it does not make any | 
|  |          | 
|  |         needsSyncChildren(false); | 
|  |  | 
|  |     } // readObject(ObjectInputStream) | 
|  |  | 
|  |      | 
|  |  | 
|  |      */ | 
|  |     class UserDataRecord implements Serializable { | 
|  |          | 
|  |         private static final long serialVersionUID = 3258126977134310455L; | 
|  |  | 
|  |         Object fData; | 
|  |         UserDataHandler fHandler; | 
|  |         UserDataRecord(Object data, UserDataHandler handler) { | 
|  |             fData = data; | 
|  |             fHandler = handler; | 
|  |         } | 
|  |     } | 
|  | } // class ParentNode |