286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/A/*
286N/A * Copyright 1999-2002,2004,2005 The Apache Software Foundation.
286N/A *
286N/A * Licensed under the Apache License, Version 2.0 (the "License");
286N/A * you may not use this file except in compliance with the License.
286N/A * You may obtain a copy of the License at
286N/A *
286N/A * http://www.apache.org/licenses/LICENSE-2.0
286N/A *
286N/A * Unless required by applicable law or agreed to in writing, software
286N/A * distributed under the License is distributed on an "AS IS" BASIS,
286N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286N/A * See the License for the specific language governing permissions and
286N/A * limitations under the License.
286N/A */
286N/A
286N/Apackage com.sun.org.apache.xerces.internal.dom;
286N/A
286N/Aimport java.util.ArrayList;
286N/A
286N/Aimport org.w3c.dom.DOMImplementation;
286N/Aimport org.w3c.dom.Element;
286N/Aimport org.w3c.dom.Node;
286N/A
286N/A/**
286N/A * The Document interface represents the entire HTML or XML document.
286N/A * Conceptually, it is the root of the document tree, and provides the
286N/A * primary access to the document's data.
286N/A * <P>
286N/A * Since elements, text nodes, comments, processing instructions,
286N/A * etc. cannot exist outside the context of a Document, the Document
286N/A * interface also contains the factory methods needed to create these
286N/A * objects. The Node objects created have a ownerDocument attribute
286N/A * which associates them with the Document within whose context they
286N/A * were created.
286N/A *
286N/A * @xerces.internal
286N/A *
286N/A * @version $Id: DeferredDocumentImpl.java,v 1.11 2010-11-01 04:39:38 joehw Exp $
286N/A * @since PR-DOM-Level-1-19980818.
286N/A */
286N/Apublic class DeferredDocumentImpl
286N/A extends DocumentImpl
286N/A implements DeferredNode {
286N/A
286N/A //
286N/A // Constants
286N/A //
286N/A
286N/A /** Serialization version. */
286N/A static final long serialVersionUID = 5186323580749626857L;
286N/A
286N/A // debugging
286N/A
286N/A /** To include code for printing the ref count tables. */
286N/A private static final boolean DEBUG_PRINT_REF_COUNTS = false;
286N/A
286N/A /** To include code for printing the internal tables. */
286N/A private static final boolean DEBUG_PRINT_TABLES = false;
286N/A
286N/A /** To debug identifiers set to true and recompile. */
286N/A private static final boolean DEBUG_IDS = false;
286N/A
286N/A // protected
286N/A
286N/A /** Chunk shift. */
286N/A protected static final int CHUNK_SHIFT = 8; // 2^8 = 256
286N/A
286N/A /** Chunk size. */
286N/A protected static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
286N/A
286N/A /** Chunk mask. */
286N/A protected static final int CHUNK_MASK = CHUNK_SIZE - 1;
286N/A
286N/A /** Initial chunk size. */
286N/A protected static final int INITIAL_CHUNK_COUNT = (1 << (13 - CHUNK_SHIFT)); // 32
286N/A
286N/A //
286N/A // Data
286N/A //
286N/A
286N/A // lazy-eval information
286N/A // To maximize memory consumption the actual semantic of these fields vary
286N/A // depending on the node type.
286N/A
286N/A /** Node count. */
286N/A protected transient int fNodeCount = 0;
286N/A
286N/A /** Node types. */
286N/A protected transient int fNodeType[][];
286N/A
286N/A /** Node names. */
286N/A protected transient Object fNodeName[][];
286N/A
286N/A /** Node values. */
286N/A protected transient Object fNodeValue[][];
286N/A
286N/A /** Node parents. */
286N/A protected transient int fNodeParent[][];
286N/A
286N/A /** Node first children. */
286N/A protected transient int fNodeLastChild[][];
286N/A
286N/A /** Node prev siblings. */
286N/A protected transient int fNodePrevSib[][];
286N/A
286N/A /** Node namespace URI. */
286N/A protected transient Object fNodeURI[][];
286N/A
286N/A /** Extra data. */
286N/A protected transient int fNodeExtra[][];
286N/A
286N/A /** Identifier count. */
286N/A protected transient int fIdCount;
286N/A
286N/A /** Identifier name indexes. */
286N/A protected transient String fIdName[];
286N/A
286N/A /** Identifier element indexes. */
286N/A protected transient int fIdElement[];
286N/A
286N/A /** DOM2: For namespace support in the deferred case.
286N/A */
286N/A // Implementation Note: The deferred element and attribute must know how to
286N/A // interpret the int representing the qname.
286N/A protected boolean fNamespacesEnabled = false;
286N/A
286N/A //
286N/A // private data
286N/A //
286N/A private transient final StringBuilder fBufferStr = new StringBuilder();
286N/A private transient final ArrayList fStrChunks = new ArrayList();
286N/A
286N/A //
286N/A // Constructors
286N/A //
286N/A
286N/A /**
286N/A * NON-DOM: Actually creating a Document is outside the DOM's spec,
286N/A * since it has to operate in terms of a particular implementation.
286N/A */
286N/A public DeferredDocumentImpl() {
286N/A this(false);
286N/A } // <init>()
286N/A
286N/A /**
286N/A * NON-DOM: Actually creating a Document is outside the DOM's spec,
286N/A * since it has to operate in terms of a particular implementation.
286N/A */
286N/A public DeferredDocumentImpl(boolean namespacesEnabled) {
286N/A this(namespacesEnabled, false);
286N/A } // <init>(boolean)
286N/A
286N/A /** Experimental constructor. */
286N/A public DeferredDocumentImpl(boolean namespaces, boolean grammarAccess) {
286N/A super(grammarAccess);
286N/A
286N/A needsSyncData(true);
286N/A needsSyncChildren(true);
286N/A
286N/A fNamespacesEnabled = namespaces;
286N/A
286N/A } // <init>(boolean,boolean)
286N/A
286N/A //
286N/A // Public methods
286N/A //
286N/A
286N/A /**
286N/A * Retrieve information describing the abilities of this particular
286N/A * DOM implementation. Intended to support applications that may be
286N/A * using DOMs retrieved from several different sources, potentially
286N/A * with different underlying representations.
286N/A */
286N/A public DOMImplementation getImplementation() {
286N/A // Currently implemented as a singleton, since it's hardcoded
286N/A // information anyway.
286N/A return DeferredDOMImplementationImpl.getDOMImplementation();
286N/A }
286N/A
286N/A /** Returns the cached parser.getNamespaces() value.*/
286N/A boolean getNamespacesEnabled() {
286N/A return fNamespacesEnabled;
286N/A }
286N/A
286N/A void setNamespacesEnabled(boolean enable) {
286N/A fNamespacesEnabled = enable;
286N/A }
286N/A
286N/A // internal factory methods
286N/A
286N/A /** Creates a document node in the table. */
286N/A public int createDeferredDocument() {
286N/A int nodeIndex = createNode(Node.DOCUMENT_NODE);
286N/A return nodeIndex;
286N/A }
286N/A
286N/A /** Creates a doctype. */
286N/A public int createDeferredDocumentType(String rootElementName,
286N/A String publicId, String systemId) {
286N/A
286N/A // create node
286N/A int nodeIndex = createNode(Node.DOCUMENT_TYPE_NODE);
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A
286N/A // save name, public id, system id
286N/A setChunkValue(fNodeName, rootElementName, chunk, index);
286N/A setChunkValue(fNodeValue, publicId, chunk, index);
286N/A setChunkValue(fNodeURI, systemId, chunk, index);
286N/A
286N/A // return node index
286N/A return nodeIndex;
286N/A
286N/A } // createDeferredDocumentType(String,String,String):int
286N/A
286N/A public void setInternalSubset(int doctypeIndex, String subset) {
286N/A int chunk = doctypeIndex >> CHUNK_SHIFT;
286N/A int index = doctypeIndex & CHUNK_MASK;
286N/A
286N/A // create extra data node to store internal subset
286N/A int extraDataIndex = createNode(Node.DOCUMENT_TYPE_NODE);
286N/A int echunk = extraDataIndex >> CHUNK_SHIFT;
286N/A int eindex = extraDataIndex & CHUNK_MASK;
286N/A setChunkIndex(fNodeExtra, extraDataIndex, chunk, index);
286N/A setChunkValue(fNodeValue, subset, echunk, eindex);
286N/A }
286N/A
286N/A /** Creates a notation in the table. */
286N/A public int createDeferredNotation(String notationName,
286N/A String publicId, String systemId, String baseURI) {
286N/A
286N/A // create node
286N/A int nodeIndex = createNode(Node.NOTATION_NODE);
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A
286N/A
286N/A // create extra data node
286N/A int extraDataIndex = createNode(Node.NOTATION_NODE);
286N/A int echunk = extraDataIndex >> CHUNK_SHIFT;
286N/A int eindex = extraDataIndex & CHUNK_MASK;
286N/A
286N/A // save name, public id, system id, and notation name
286N/A setChunkValue(fNodeName, notationName, chunk, index);
286N/A setChunkValue(fNodeValue, publicId, chunk, index);
286N/A setChunkValue(fNodeURI, systemId, chunk, index);
286N/A
286N/A // in extra data node set baseURI value
286N/A setChunkIndex(fNodeExtra, extraDataIndex, chunk, index);
286N/A setChunkValue(fNodeName, baseURI, echunk, eindex);
286N/A
286N/A // return node index
286N/A return nodeIndex;
286N/A
286N/A } // createDeferredNotation(String,String,String):int
286N/A
286N/A /** Creates an entity in the table. */
286N/A public int createDeferredEntity(String entityName, String publicId,
286N/A String systemId, String notationName,
286N/A String baseURI) {
286N/A // create node
286N/A int nodeIndex = createNode(Node.ENTITY_NODE);
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A
286N/A // create extra data node
286N/A int extraDataIndex = createNode(Node.ENTITY_NODE);
286N/A int echunk = extraDataIndex >> CHUNK_SHIFT;
286N/A int eindex = extraDataIndex & CHUNK_MASK;
286N/A
286N/A // save name, public id, system id, and notation name
286N/A setChunkValue(fNodeName, entityName, chunk, index);
286N/A setChunkValue(fNodeValue, publicId, chunk, index);
286N/A setChunkValue(fNodeURI, systemId, chunk, index);
286N/A setChunkIndex(fNodeExtra, extraDataIndex, chunk, index);
286N/A // set other values in the extra chunk
286N/A // notation
286N/A setChunkValue(fNodeName, notationName, echunk, eindex);
286N/A // version L3
286N/A setChunkValue(fNodeValue, null, echunk, eindex);
286N/A // encoding L3
286N/A setChunkValue(fNodeURI, null, echunk, eindex);
286N/A
286N/A
286N/A int extraDataIndex2 = createNode(Node.ENTITY_NODE);
286N/A int echunk2 = extraDataIndex2 >> CHUNK_SHIFT;
286N/A int eindex2 = extraDataIndex2 & CHUNK_MASK;
286N/A
286N/A setChunkIndex(fNodeExtra, extraDataIndex2, echunk, eindex);
286N/A
286N/A // baseURI
286N/A setChunkValue(fNodeName, baseURI, echunk2, eindex2);
286N/A
286N/A // return node index
286N/A return nodeIndex;
286N/A
286N/A } // createDeferredEntity(String,String,String,String):int
286N/A
286N/A public String getDeferredEntityBaseURI (int entityIndex){
286N/A if (entityIndex != -1) {
286N/A int extraDataIndex = getNodeExtra(entityIndex, false);
286N/A extraDataIndex = getNodeExtra(extraDataIndex, false);
286N/A return getNodeName (extraDataIndex, false);
286N/A }
286N/A return null;
286N/A }
286N/A
286N/A // DOM Level 3: setting encoding and version
286N/A public void setEntityInfo(int currentEntityDecl,
286N/A String version, String encoding){
286N/A int eNodeIndex = getNodeExtra(currentEntityDecl, false);
286N/A if (eNodeIndex !=-1) {
286N/A int echunk = eNodeIndex >> CHUNK_SHIFT;
286N/A int eindex = eNodeIndex & CHUNK_MASK;
286N/A setChunkValue(fNodeValue, version, echunk, eindex);
286N/A setChunkValue(fNodeURI, encoding, echunk, eindex);
286N/A }
286N/A }
286N/A
286N/A // DOM Level 3: sets element TypeInfo
286N/A public void setTypeInfo(int elementNodeIndex, Object type) {
286N/A int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
286N/A int elementIndex = elementNodeIndex & CHUNK_MASK;
286N/A setChunkValue(fNodeValue, type, elementChunk, elementIndex);
286N/A }
286N/A
286N/A /**
286N/A * DOM Internal
286N/A *
286N/A * An attribute specifying the actual encoding of this document. This is
286N/A * <code>null</code> otherwise.
286N/A * <br> This attribute represents the property [character encoding scheme]
286N/A * defined in .
286N/A */
286N/A public void setInputEncoding(int currentEntityDecl, String value){
286N/A // get first extra data chunk
286N/A int nodeIndex = getNodeExtra(currentEntityDecl, false);
286N/A // get second extra data chunk
286N/A int extraDataIndex = getNodeExtra(nodeIndex, false);
286N/A
286N/A int echunk = extraDataIndex >> CHUNK_SHIFT;
286N/A int eindex = extraDataIndex & CHUNK_MASK;
286N/A
286N/A setChunkValue(fNodeValue, value, echunk, eindex);
286N/A
286N/A }
286N/A
286N/A /** Creates an entity reference node in the table. */
286N/A public int createDeferredEntityReference(String name, String baseURI) {
286N/A
286N/A // create node
286N/A int nodeIndex = createNode(Node.ENTITY_REFERENCE_NODE);
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A setChunkValue(fNodeName, name, chunk, index);
286N/A setChunkValue(fNodeValue, baseURI, chunk, index);
286N/A
286N/A // return node index
286N/A return nodeIndex;
286N/A
286N/A } // createDeferredEntityReference(String):int
286N/A
286N/A
286N/A /**
286N/A * Creates an element node with a URI in the table and type information.
286N/A * @deprecated
286N/A */
286N/A public int createDeferredElement(String elementURI, String elementName,
286N/A Object type) {
286N/A
286N/A // create node
286N/A int elementNodeIndex = createNode(Node.ELEMENT_NODE);
286N/A int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
286N/A int elementIndex = elementNodeIndex & CHUNK_MASK;
286N/A setChunkValue(fNodeName, elementName, elementChunk, elementIndex);
286N/A setChunkValue(fNodeURI, elementURI, elementChunk, elementIndex);
286N/A setChunkValue(fNodeValue, type, elementChunk, elementIndex);
286N/A
286N/A // return node index
286N/A return elementNodeIndex;
286N/A
286N/A } // createDeferredElement(String,String,Object):int
286N/A
286N/A /**
286N/A * Creates an element node in the table.
286N/A * @deprecated
286N/A */
286N/A public int createDeferredElement(String elementName) {
286N/A return createDeferredElement(null, elementName);
286N/A }
286N/A
286N/A /**
286N/A * Creates an element node with a URI in the table.
286N/A */
286N/A public int createDeferredElement(String elementURI, String elementName) {
286N/A
286N/A // create node
286N/A int elementNodeIndex = createNode(Node.ELEMENT_NODE);
286N/A int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
286N/A int elementIndex = elementNodeIndex & CHUNK_MASK;
286N/A setChunkValue(fNodeName, elementName, elementChunk, elementIndex);
286N/A setChunkValue(fNodeURI, elementURI, elementChunk, elementIndex);
286N/A
286N/A // return node index
286N/A return elementNodeIndex;
286N/A
286N/A } // createDeferredElement(String,String):int
286N/A
286N/A
286N/A /**
286N/A * This method is used by the DOMParser to create attributes.
286N/A * @param elementNodeIndex
286N/A * @param attrName
286N/A * @param attrURI
286N/A * @param attrValue
286N/A * @param specified
286N/A * @param id
286N/A * @param type
286N/A * @return int
286N/A */
286N/A public int setDeferredAttribute(int elementNodeIndex,
286N/A String attrName,
286N/A String attrURI,
286N/A String attrValue,
286N/A boolean specified,
286N/A boolean id,
286N/A Object type) {
286N/A
286N/A // create attribute
286N/A int attrNodeIndex = createDeferredAttribute(attrName, attrURI, attrValue, specified);
286N/A int attrChunk = attrNodeIndex >> CHUNK_SHIFT;
286N/A int attrIndex = attrNodeIndex & CHUNK_MASK;
286N/A // set attribute's parent to element
286N/A setChunkIndex(fNodeParent, elementNodeIndex, attrChunk, attrIndex);
286N/A
286N/A int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
286N/A int elementIndex = elementNodeIndex & CHUNK_MASK;
286N/A
286N/A // get element's last attribute
286N/A int lastAttrNodeIndex = getChunkIndex(fNodeExtra, elementChunk, elementIndex);
286N/A if (lastAttrNodeIndex != 0) {
286N/A // add link from new attribute to last attribute
286N/A setChunkIndex(fNodePrevSib, lastAttrNodeIndex, attrChunk, attrIndex);
286N/A }
286N/A // add link from element to new last attribute
286N/A setChunkIndex(fNodeExtra, attrNodeIndex, elementChunk, elementIndex);
286N/A
286N/A int extra = getChunkIndex(fNodeExtra, attrChunk, attrIndex);
286N/A if (id) {
286N/A extra = extra | ID;
286N/A setChunkIndex(fNodeExtra, extra, attrChunk, attrIndex);
286N/A String value = getChunkValue(fNodeValue, attrChunk, attrIndex);
286N/A putIdentifier(value, elementNodeIndex);
286N/A }
286N/A // store type information
286N/A if (type != null) {
286N/A int extraDataIndex = createNode(DeferredNode.TYPE_NODE);
286N/A int echunk = extraDataIndex >> CHUNK_SHIFT;
286N/A int eindex = extraDataIndex & CHUNK_MASK;
286N/A
286N/A setChunkIndex(fNodeLastChild, extraDataIndex, attrChunk, attrIndex);
286N/A setChunkValue(fNodeValue, type, echunk, eindex);
286N/A }
286N/A
286N/A // return node index
286N/A return attrNodeIndex;
286N/A }
286N/A
286N/A /**
286N/A * Sets an attribute on an element node.
286N/A * @deprecated
286N/A */
286N/A public int setDeferredAttribute(int elementNodeIndex,
286N/A String attrName, String attrURI,
286N/A String attrValue, boolean specified) {
286N/A // create attribute
286N/A int attrNodeIndex = createDeferredAttribute(attrName, attrURI,
286N/A attrValue, specified);
286N/A int attrChunk = attrNodeIndex >> CHUNK_SHIFT;
286N/A int attrIndex = attrNodeIndex & CHUNK_MASK;
286N/A // set attribute's parent to element
286N/A setChunkIndex(fNodeParent, elementNodeIndex, attrChunk, attrIndex);
286N/A
286N/A int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
286N/A int elementIndex = elementNodeIndex & CHUNK_MASK;
286N/A
286N/A // get element's last attribute
286N/A int lastAttrNodeIndex = getChunkIndex(fNodeExtra,
286N/A elementChunk, elementIndex);
286N/A if (lastAttrNodeIndex != 0) {
286N/A // add link from new attribute to last attribute
286N/A setChunkIndex(fNodePrevSib, lastAttrNodeIndex,
286N/A attrChunk, attrIndex);
286N/A }
286N/A // add link from element to new last attribute
286N/A setChunkIndex(fNodeExtra, attrNodeIndex,
286N/A elementChunk, elementIndex);
286N/A
286N/A // return node index
286N/A return attrNodeIndex;
286N/A
286N/A } // setDeferredAttribute(int,String,String,String,boolean):int
286N/A
286N/A /** Creates an attribute in the table. */
286N/A public int createDeferredAttribute(String attrName, String attrValue,
286N/A boolean specified) {
286N/A return createDeferredAttribute(attrName, null, attrValue, specified);
286N/A }
286N/A
286N/A /** Creates an attribute with a URI in the table. */
286N/A public int createDeferredAttribute(String attrName, String attrURI,
286N/A String attrValue, boolean specified) {
286N/A
286N/A // create node
286N/A int nodeIndex = createNode(NodeImpl.ATTRIBUTE_NODE);
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A setChunkValue(fNodeName, attrName, chunk, index);
286N/A setChunkValue(fNodeURI, attrURI, chunk, index);
286N/A setChunkValue(fNodeValue, attrValue, chunk, index);
286N/A int extra = specified ? SPECIFIED : 0;
286N/A setChunkIndex(fNodeExtra, extra, chunk, index);
286N/A
286N/A // return node index
286N/A return nodeIndex;
286N/A
286N/A } // createDeferredAttribute(String,String,String,boolean):int
286N/A
286N/A /** Creates an element definition in the table.*/
286N/A public int createDeferredElementDefinition(String elementName) {
286N/A
286N/A // create node
286N/A int nodeIndex = createNode(NodeImpl.ELEMENT_DEFINITION_NODE);
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A setChunkValue(fNodeName, elementName, chunk, index);
286N/A
286N/A // return node index
286N/A return nodeIndex;
286N/A
286N/A } // createDeferredElementDefinition(String):int
286N/A
286N/A /** Creates a text node in the table. */
286N/A public int createDeferredTextNode(String data,
286N/A boolean ignorableWhitespace) {
286N/A
286N/A // create node
286N/A int nodeIndex = createNode(Node.TEXT_NODE);
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A setChunkValue(fNodeValue, data, chunk, index);
286N/A // use extra to store ignorableWhitespace info
286N/A setChunkIndex(fNodeExtra, ignorableWhitespace ? 1 : 0, chunk, index);
286N/A
286N/A // return node index
286N/A return nodeIndex;
286N/A
286N/A } // createDeferredTextNode(String,boolean):int
286N/A
286N/A /** Creates a CDATA section node in the table. */
286N/A public int createDeferredCDATASection(String data) {
286N/A
286N/A // create node
286N/A int nodeIndex = createNode(Node.CDATA_SECTION_NODE);
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A setChunkValue(fNodeValue, data, chunk, index);
286N/A
286N/A // return node index
286N/A return nodeIndex;
286N/A
286N/A } // createDeferredCDATASection(String):int
286N/A
286N/A /** Creates a processing instruction node in the table. */
286N/A public int createDeferredProcessingInstruction(String target,
286N/A String data) {
286N/A // create node
286N/A int nodeIndex = createNode(Node.PROCESSING_INSTRUCTION_NODE);
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A setChunkValue(fNodeName, target, chunk, index);
286N/A setChunkValue(fNodeValue, data, chunk, index);
286N/A // return node index
286N/A return nodeIndex;
286N/A
286N/A } // createDeferredProcessingInstruction(String,String):int
286N/A
286N/A /** Creates a comment node in the table. */
286N/A public int createDeferredComment(String data) {
286N/A
286N/A // create node
286N/A int nodeIndex = createNode(Node.COMMENT_NODE);
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A setChunkValue(fNodeValue, data, chunk, index);
286N/A
286N/A // return node index
286N/A return nodeIndex;
286N/A
286N/A } // createDeferredComment(String):int
286N/A
286N/A /** Creates a clone of the specified node. */
286N/A public int cloneNode(int nodeIndex, boolean deep) {
286N/A
286N/A // clone immediate node
286N/A
286N/A int nchunk = nodeIndex >> CHUNK_SHIFT;
286N/A int nindex = nodeIndex & CHUNK_MASK;
286N/A int nodeType = fNodeType[nchunk][nindex];
286N/A int cloneIndex = createNode((short)nodeType);
286N/A int cchunk = cloneIndex >> CHUNK_SHIFT;
286N/A int cindex = cloneIndex & CHUNK_MASK;
286N/A setChunkValue(fNodeName, fNodeName[nchunk][nindex], cchunk, cindex);
286N/A setChunkValue(fNodeValue, fNodeValue[nchunk][nindex], cchunk, cindex);
286N/A setChunkValue(fNodeURI, fNodeURI[nchunk][nindex], cchunk, cindex);
286N/A int extraIndex = fNodeExtra[nchunk][nindex];
286N/A if (extraIndex != -1) {
286N/A if (nodeType != Node.ATTRIBUTE_NODE && nodeType != Node.TEXT_NODE) {
286N/A extraIndex = cloneNode(extraIndex, false);
286N/A }
286N/A setChunkIndex(fNodeExtra, extraIndex, cchunk, cindex);
286N/A }
286N/A
286N/A // clone and attach children
286N/A if (deep) {
286N/A int prevIndex = -1;
286N/A int childIndex = getLastChild(nodeIndex, false);
286N/A while (childIndex != -1) {
286N/A int clonedChildIndex = cloneNode(childIndex, deep);
286N/A insertBefore(cloneIndex, clonedChildIndex, prevIndex);
286N/A prevIndex = clonedChildIndex;
286N/A childIndex = getRealPrevSibling(childIndex, false);
286N/A }
286N/A
286N/A
286N/A }
286N/A
286N/A // return cloned node index
286N/A return cloneIndex;
286N/A
286N/A } // cloneNode(int,boolean):int
286N/A
286N/A /** Appends a child to the specified parent in the table. */
286N/A public void appendChild(int parentIndex, int childIndex) {
286N/A
286N/A // append parent index
286N/A int pchunk = parentIndex >> CHUNK_SHIFT;
286N/A int pindex = parentIndex & CHUNK_MASK;
286N/A int cchunk = childIndex >> CHUNK_SHIFT;
286N/A int cindex = childIndex & CHUNK_MASK;
286N/A setChunkIndex(fNodeParent, parentIndex, cchunk, cindex);
286N/A
286N/A // set previous sibling of new child
286N/A int olast = getChunkIndex(fNodeLastChild, pchunk, pindex);
286N/A setChunkIndex(fNodePrevSib, olast, cchunk, cindex);
286N/A
286N/A // update parent's last child
286N/A setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex);
286N/A
286N/A } // appendChild(int,int)
286N/A
286N/A /** Adds an attribute node to the specified element. */
286N/A public int setAttributeNode(int elemIndex, int attrIndex) {
286N/A
286N/A int echunk = elemIndex >> CHUNK_SHIFT;
286N/A int eindex = elemIndex & CHUNK_MASK;
286N/A int achunk = attrIndex >> CHUNK_SHIFT;
286N/A int aindex = attrIndex & CHUNK_MASK;
286N/A
286N/A // see if this attribute is already here
286N/A String attrName = getChunkValue(fNodeName, achunk, aindex);
286N/A int oldAttrIndex = getChunkIndex(fNodeExtra, echunk, eindex);
286N/A int nextIndex = -1;
286N/A int oachunk = -1;
286N/A int oaindex = -1;
286N/A while (oldAttrIndex != -1) {
286N/A oachunk = oldAttrIndex >> CHUNK_SHIFT;
286N/A oaindex = oldAttrIndex & CHUNK_MASK;
286N/A String oldAttrName = getChunkValue(fNodeName, oachunk, oaindex);
286N/A if (oldAttrName.equals(attrName)) {
286N/A break;
286N/A }
286N/A nextIndex = oldAttrIndex;
286N/A oldAttrIndex = getChunkIndex(fNodePrevSib, oachunk, oaindex);
286N/A }
286N/A
286N/A // remove old attribute
286N/A if (oldAttrIndex != -1) {
286N/A
286N/A // patch links
286N/A int prevIndex = getChunkIndex(fNodePrevSib, oachunk, oaindex);
286N/A if (nextIndex == -1) {
286N/A setChunkIndex(fNodeExtra, prevIndex, echunk, eindex);
286N/A }
286N/A else {
286N/A int pchunk = nextIndex >> CHUNK_SHIFT;
286N/A int pindex = nextIndex & CHUNK_MASK;
286N/A setChunkIndex(fNodePrevSib, prevIndex, pchunk, pindex);
286N/A }
286N/A
286N/A // remove connections to siblings
286N/A clearChunkIndex(fNodeType, oachunk, oaindex);
286N/A clearChunkValue(fNodeName, oachunk, oaindex);
286N/A clearChunkValue(fNodeValue, oachunk, oaindex);
286N/A clearChunkIndex(fNodeParent, oachunk, oaindex);
286N/A clearChunkIndex(fNodePrevSib, oachunk, oaindex);
286N/A int attrTextIndex =
286N/A clearChunkIndex(fNodeLastChild, oachunk, oaindex);
286N/A int atchunk = attrTextIndex >> CHUNK_SHIFT;
286N/A int atindex = attrTextIndex & CHUNK_MASK;
286N/A clearChunkIndex(fNodeType, atchunk, atindex);
286N/A clearChunkValue(fNodeValue, atchunk, atindex);
286N/A clearChunkIndex(fNodeParent, atchunk, atindex);
286N/A clearChunkIndex(fNodeLastChild, atchunk, atindex);
286N/A }
286N/A
286N/A // add new attribute
286N/A int prevIndex = getChunkIndex(fNodeExtra, echunk, eindex);
286N/A setChunkIndex(fNodeExtra, attrIndex, echunk, eindex);
286N/A setChunkIndex(fNodePrevSib, prevIndex, achunk, aindex);
286N/A
286N/A // return
286N/A return oldAttrIndex;
286N/A
286N/A } // setAttributeNode(int,int):int
286N/A
286N/A
286N/A /** Adds an attribute node to the specified element. */
286N/A public void setIdAttributeNode(int elemIndex, int attrIndex) {
286N/A
286N/A int chunk = attrIndex >> CHUNK_SHIFT;
286N/A int index = attrIndex & CHUNK_MASK;
286N/A int extra = getChunkIndex(fNodeExtra, chunk, index);
286N/A extra = extra | ID;
286N/A setChunkIndex(fNodeExtra, extra, chunk, index);
286N/A
286N/A String value = getChunkValue(fNodeValue, chunk, index);
286N/A putIdentifier(value, elemIndex);
286N/A }
286N/A
286N/A
286N/A /** Sets type of attribute */
286N/A public void setIdAttribute(int attrIndex) {
286N/A
286N/A int chunk = attrIndex >> CHUNK_SHIFT;
286N/A int index = attrIndex & CHUNK_MASK;
286N/A int extra = getChunkIndex(fNodeExtra, chunk, index);
286N/A extra = extra | ID;
286N/A setChunkIndex(fNodeExtra, extra, chunk, index);
286N/A }
286N/A
286N/A /** Inserts a child before the specified node in the table. */
286N/A public int insertBefore(int parentIndex, int newChildIndex, int refChildIndex) {
286N/A
286N/A if (refChildIndex == -1) {
286N/A appendChild(parentIndex, newChildIndex);
286N/A return newChildIndex;
286N/A }
286N/A
286N/A int nchunk = newChildIndex >> CHUNK_SHIFT;
286N/A int nindex = newChildIndex & CHUNK_MASK;
286N/A int rchunk = refChildIndex >> CHUNK_SHIFT;
286N/A int rindex = refChildIndex & CHUNK_MASK;
286N/A int previousIndex = getChunkIndex(fNodePrevSib, rchunk, rindex);
286N/A setChunkIndex(fNodePrevSib, newChildIndex, rchunk, rindex);
286N/A setChunkIndex(fNodePrevSib, previousIndex, nchunk, nindex);
286N/A
286N/A return newChildIndex;
286N/A
286N/A } // insertBefore(int,int,int):int
286N/A
286N/A /** Sets the last child of the parentIndex to childIndex. */
286N/A public void setAsLastChild(int parentIndex, int childIndex) {
286N/A int pchunk = parentIndex >> CHUNK_SHIFT;
286N/A int pindex = parentIndex & CHUNK_MASK;
286N/A setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex);
286N/A } // setAsLastChild(int,int)
286N/A
286N/A /**
286N/A * Returns the parent node of the given node.
286N/A * <em>Calling this method does not free the parent index.</em>
286N/A */
286N/A public int getParentNode(int nodeIndex) {
286N/A return getParentNode(nodeIndex, false);
286N/A }
286N/A
286N/A /**
286N/A * Returns the parent node of the given node.
286N/A * @param free True to free parent node.
286N/A */
286N/A public int getParentNode(int nodeIndex, boolean free) {
286N/A
286N/A if (nodeIndex == -1) {
286N/A return -1;
286N/A }
286N/A
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A return free ? clearChunkIndex(fNodeParent, chunk, index)
286N/A : getChunkIndex(fNodeParent, chunk, index);
286N/A
286N/A } // getParentNode(int):int
286N/A
286N/A /** Returns the last child of the given node. */
286N/A public int getLastChild(int nodeIndex) {
286N/A return getLastChild(nodeIndex, true);
286N/A }
286N/A
286N/A /**
286N/A * Returns the last child of the given node.
286N/A * @param free True to free child index.
286N/A */
286N/A public int getLastChild(int nodeIndex, boolean free) {
286N/A
286N/A if (nodeIndex == -1) {
286N/A return -1;
286N/A }
286N/A
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A return free ? clearChunkIndex(fNodeLastChild, chunk, index)
286N/A : getChunkIndex(fNodeLastChild, chunk, index);
286N/A
286N/A } // getLastChild(int,boolean):int
286N/A
286N/A /**
286N/A * Returns the prev sibling of the given node.
286N/A * This is post-normalization of Text Nodes.
286N/A */
286N/A public int getPrevSibling(int nodeIndex) {
286N/A return getPrevSibling(nodeIndex, true);
286N/A }
286N/A
286N/A /**
286N/A * Returns the prev sibling of the given node.
286N/A * @param free True to free sibling index.
286N/A */
286N/A public int getPrevSibling(int nodeIndex, boolean free) {
286N/A
286N/A if (nodeIndex == -1) {
286N/A return -1;
286N/A }
286N/A
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A int type = getChunkIndex(fNodeType, chunk, index);
286N/A if (type == Node.TEXT_NODE) {
286N/A do {
286N/A nodeIndex = getChunkIndex(fNodePrevSib, chunk, index);
286N/A if (nodeIndex == -1) {
286N/A break;
286N/A }
286N/A chunk = nodeIndex >> CHUNK_SHIFT;
286N/A index = nodeIndex & CHUNK_MASK;
286N/A type = getChunkIndex(fNodeType, chunk, index);
286N/A } while (type == Node.TEXT_NODE);
286N/A }
286N/A else {
286N/A nodeIndex = getChunkIndex(fNodePrevSib, chunk, index);
286N/A }
286N/A
286N/A return nodeIndex;
286N/A
286N/A } // getPrevSibling(int,boolean):int
286N/A
286N/A /**
286N/A * Returns the <i>real</i> prev sibling of the given node,
286N/A * directly from the data structures. Used by TextImpl#getNodeValue()
286N/A * to normalize values.
286N/A */
286N/A public int getRealPrevSibling(int nodeIndex) {
286N/A return getRealPrevSibling(nodeIndex, true);
286N/A }
286N/A
286N/A /**
286N/A * Returns the <i>real</i> prev sibling of the given node.
286N/A * @param free True to free sibling index.
286N/A */
286N/A public int getRealPrevSibling(int nodeIndex, boolean free) {
286N/A
286N/A if (nodeIndex == -1) {
286N/A return -1;
286N/A }
286N/A
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A return free ? clearChunkIndex(fNodePrevSib, chunk, index)
286N/A : getChunkIndex(fNodePrevSib, chunk, index);
286N/A
286N/A } // getReadPrevSibling(int,boolean):int
286N/A
286N/A /**
286N/A * Returns the index of the element definition in the table
286N/A * with the specified name index, or -1 if no such definition
286N/A * exists.
286N/A */
286N/A public int lookupElementDefinition(String elementName) {
286N/A
286N/A if (fNodeCount > 1) {
286N/A
286N/A // find doctype
286N/A int docTypeIndex = -1;
286N/A int nchunk = 0;
286N/A int nindex = 0;
286N/A for (int index = getChunkIndex(fNodeLastChild, nchunk, nindex);
286N/A index != -1;
286N/A index = getChunkIndex(fNodePrevSib, nchunk, nindex)) {
286N/A
286N/A nchunk = index >> CHUNK_SHIFT;
286N/A nindex = index & CHUNK_MASK;
286N/A if (getChunkIndex(fNodeType, nchunk, nindex) == Node.DOCUMENT_TYPE_NODE) {
286N/A docTypeIndex = index;
286N/A break;
286N/A }
286N/A }
286N/A
286N/A // find element definition
286N/A if (docTypeIndex == -1) {
286N/A return -1;
286N/A }
286N/A nchunk = docTypeIndex >> CHUNK_SHIFT;
286N/A nindex = docTypeIndex & CHUNK_MASK;
286N/A for (int index = getChunkIndex(fNodeLastChild, nchunk, nindex);
286N/A index != -1;
286N/A index = getChunkIndex(fNodePrevSib, nchunk, nindex)) {
286N/A
286N/A nchunk = index >> CHUNK_SHIFT;
286N/A nindex = index & CHUNK_MASK;
286N/A if (getChunkIndex(fNodeType, nchunk, nindex) ==
286N/A NodeImpl.ELEMENT_DEFINITION_NODE
286N/A && getChunkValue(fNodeName, nchunk, nindex) == elementName) {
286N/A return index;
286N/A }
286N/A }
286N/A }
286N/A
286N/A return -1;
286N/A
286N/A } // lookupElementDefinition(String):int
286N/A
286N/A /** Instantiates the requested node object. */
286N/A public DeferredNode getNodeObject(int nodeIndex) {
286N/A
286N/A // is there anything to do?
286N/A if (nodeIndex == -1) {
286N/A return null;
286N/A }
286N/A
286N/A // get node type
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A int type = getChunkIndex(fNodeType, chunk, index);
286N/A if (type != Node.TEXT_NODE && type != Node.CDATA_SECTION_NODE) {
286N/A clearChunkIndex(fNodeType, chunk, index);
286N/A }
286N/A
286N/A // create new node
286N/A DeferredNode node = null;
286N/A switch (type) {
286N/A
286N/A //
286N/A // Standard DOM node types
286N/A //
286N/A
286N/A case Node.ATTRIBUTE_NODE: {
286N/A if (fNamespacesEnabled) {
286N/A node = new DeferredAttrNSImpl(this, nodeIndex);
286N/A } else {
286N/A node = new DeferredAttrImpl(this, nodeIndex);
286N/A }
286N/A break;
286N/A }
286N/A
286N/A case Node.CDATA_SECTION_NODE: {
286N/A node = new DeferredCDATASectionImpl(this, nodeIndex);
286N/A break;
286N/A }
286N/A
286N/A case Node.COMMENT_NODE: {
286N/A node = new DeferredCommentImpl(this, nodeIndex);
286N/A break;
286N/A }
286N/A
286N/A // NOTE: Document fragments can never be "fast".
286N/A //
286N/A // The parser will never ask to create a document
286N/A // fragment during the parse. Document fragments
286N/A // are used by the application *after* the parse.
286N/A //
286N/A // case Node.DOCUMENT_FRAGMENT_NODE: { break; }
286N/A case Node.DOCUMENT_NODE: {
286N/A // this node is never "fast"
286N/A node = this;
286N/A break;
286N/A }
286N/A
286N/A case Node.DOCUMENT_TYPE_NODE: {
286N/A node = new DeferredDocumentTypeImpl(this, nodeIndex);
286N/A // save the doctype node
286N/A docType = (DocumentTypeImpl)node;
286N/A break;
286N/A }
286N/A
286N/A case Node.ELEMENT_NODE: {
286N/A
286N/A if (DEBUG_IDS) {
286N/A System.out.println("getNodeObject(ELEMENT_NODE): "+nodeIndex);
286N/A }
286N/A
286N/A // create node
286N/A if (fNamespacesEnabled) {
286N/A node = new DeferredElementNSImpl(this, nodeIndex);
286N/A } else {
286N/A node = new DeferredElementImpl(this, nodeIndex);
286N/A }
286N/A
286N/A // check to see if this element needs to be
286N/A // registered for its ID attributes
286N/A if (fIdElement != null) {
286N/A int idIndex = binarySearch(fIdElement, 0,
286N/A fIdCount-1, nodeIndex);
286N/A while (idIndex != -1) {
286N/A
286N/A if (DEBUG_IDS) {
286N/A System.out.println(" id index: "+idIndex);
286N/A System.out.println(" fIdName["+idIndex+
286N/A "]: "+fIdName[idIndex]);
286N/A }
286N/A
286N/A // register ID
286N/A String name = fIdName[idIndex];
286N/A if (name != null) {
286N/A if (DEBUG_IDS) {
286N/A System.out.println(" name: "+name);
286N/A System.out.print("getNodeObject()#");
286N/A }
286N/A putIdentifier0(name, (Element)node);
286N/A fIdName[idIndex] = null;
286N/A }
286N/A
286N/A // continue if there are more IDs for
286N/A // this element
286N/A if (idIndex + 1 < fIdCount &&
286N/A fIdElement[idIndex + 1] == nodeIndex) {
286N/A idIndex++;
286N/A }
286N/A else {
286N/A idIndex = -1;
286N/A }
286N/A }
286N/A }
286N/A break;
286N/A }
286N/A
286N/A case Node.ENTITY_NODE: {
286N/A node = new DeferredEntityImpl(this, nodeIndex);
286N/A break;
286N/A }
286N/A
286N/A case Node.ENTITY_REFERENCE_NODE: {
286N/A node = new DeferredEntityReferenceImpl(this, nodeIndex);
286N/A break;
286N/A }
286N/A
286N/A case Node.NOTATION_NODE: {
286N/A node = new DeferredNotationImpl(this, nodeIndex);
286N/A break;
286N/A }
286N/A
286N/A case Node.PROCESSING_INSTRUCTION_NODE: {
286N/A node = new DeferredProcessingInstructionImpl(this, nodeIndex);
286N/A break;
286N/A }
286N/A
286N/A case Node.TEXT_NODE: {
286N/A node = new DeferredTextImpl(this, nodeIndex);
286N/A break;
286N/A }
286N/A
286N/A //
286N/A // non-standard DOM node types
286N/A //
286N/A
286N/A case NodeImpl.ELEMENT_DEFINITION_NODE: {
286N/A node = new DeferredElementDefinitionImpl(this, nodeIndex);
286N/A break;
286N/A }
286N/A
286N/A default: {
286N/A throw new IllegalArgumentException("type: "+type);
286N/A }
286N/A
286N/A } // switch node type
286N/A
286N/A // store and return
286N/A if (node != null) {
286N/A return node;
286N/A }
286N/A
286N/A // error
286N/A throw new IllegalArgumentException();
286N/A
286N/A } // createNodeObject(int):Node
286N/A
286N/A /** Returns the name of the given node. */
286N/A public String getNodeName(int nodeIndex) {
286N/A return getNodeName(nodeIndex, true);
286N/A } // getNodeNameString(int):String
286N/A
286N/A /**
286N/A * Returns the name of the given node.
286N/A * @param free True to free the string index.
286N/A */
286N/A public String getNodeName(int nodeIndex, boolean free) {
286N/A
286N/A if (nodeIndex == -1) {
286N/A return null;
286N/A }
286N/A
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A return free ? clearChunkValue(fNodeName, chunk, index)
286N/A : getChunkValue(fNodeName, chunk, index);
286N/A
286N/A } // getNodeName(int,boolean):String
286N/A
286N/A /** Returns the real value of the given node. */
286N/A public String getNodeValueString(int nodeIndex) {
286N/A return getNodeValueString(nodeIndex, true);
286N/A } // getNodeValueString(int):String
286N/A
286N/A /**
286N/A * Returns the real value of the given node.
286N/A * @param free True to free the string index.
286N/A */
286N/A public String getNodeValueString(int nodeIndex, boolean free) {
286N/A
286N/A if (nodeIndex == -1) {
286N/A return null;
286N/A }
286N/A
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A String value = free ? clearChunkValue(fNodeValue, chunk, index)
286N/A : getChunkValue(fNodeValue, chunk, index);
286N/A if (value == null) {
286N/A return null;
286N/A }
286N/A
286N/A int type = getChunkIndex(fNodeType, chunk, index);
286N/A if (type == Node.TEXT_NODE) {
286N/A int prevSib = getRealPrevSibling(nodeIndex);
286N/A if (prevSib != -1 &&
286N/A getNodeType(prevSib, false) == Node.TEXT_NODE) {
286N/A // append data that is stored in fNodeValue
286N/A // REVISIT: for text nodes it works differently than for CDATA
286N/A // nodes.
286N/A fStrChunks.add(value);
286N/A do {
286N/A // go in reverse order: find last child, then
286N/A // its previous sibling, etc
286N/A chunk = prevSib >> CHUNK_SHIFT;
286N/A index = prevSib & CHUNK_MASK;
286N/A value = getChunkValue(fNodeValue, chunk, index);
286N/A fStrChunks.add(value);
286N/A prevSib = getChunkIndex(fNodePrevSib, chunk, index);
286N/A if (prevSib == -1) {
286N/A break;
286N/A }
286N/A } while (getNodeType(prevSib, false) == Node.TEXT_NODE);
286N/A
286N/A int chunkCount = fStrChunks.size();
286N/A
286N/A // add to the buffer in the correct order.
286N/A for (int i = chunkCount - 1; i >= 0; i--) {
286N/A fBufferStr.append((String)fStrChunks.get(i));
286N/A }
286N/A
286N/A value = fBufferStr.toString();
286N/A fStrChunks.clear();
286N/A fBufferStr.setLength(0);
286N/A return value;
286N/A }
286N/A }
286N/A else if (type == Node.CDATA_SECTION_NODE) {
286N/A // find if any other data stored in children
286N/A int child = getLastChild(nodeIndex, false);
286N/A if (child !=-1) {
286N/A // append data that is stored in fNodeValue
286N/A fBufferStr.append(value);
286N/A while (child !=-1) {
286N/A // go in reverse order: find last child, then
286N/A // its previous sibling, etc
286N/A chunk = child >> CHUNK_SHIFT;
286N/A index = child & CHUNK_MASK;
286N/A value = getChunkValue(fNodeValue, chunk, index);
286N/A fStrChunks.add(value);
286N/A child = getChunkIndex(fNodePrevSib, chunk, index);
286N/A }
286N/A // add to the buffer in the correct order.
286N/A for (int i=fStrChunks.size()-1; i>=0; i--) {
286N/A fBufferStr.append((String)fStrChunks.get(i));
286N/A }
286N/A
286N/A value = fBufferStr.toString();
286N/A fStrChunks.clear();
286N/A fBufferStr.setLength(0);
286N/A return value;
286N/A }
286N/A }
286N/A
286N/A return value;
286N/A
286N/A } // getNodeValueString(int,boolean):String
286N/A
286N/A /**
286N/A * Returns the value of the given node.
286N/A */
286N/A public String getNodeValue(int nodeIndex) {
286N/A return getNodeValue(nodeIndex, true);
286N/A }
286N/A
286N/A /**
286N/A * Clears the type info that is stored in the fNodeValue array
286N/A * @param nodeIndex
286N/A * @return Object - type information for the attribute/element node
286N/A */
286N/A public Object getTypeInfo(int nodeIndex) {
286N/A if (nodeIndex == -1) {
286N/A return null;
286N/A }
286N/A
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A
286N/A
286N/A Object value = fNodeValue[chunk] != null ? fNodeValue[chunk][index] : null;
286N/A if (value != null) {
286N/A fNodeValue[chunk][index] = null;
286N/A RefCount c = (RefCount) fNodeValue[chunk][CHUNK_SIZE];
286N/A c.fCount--;
286N/A if (c.fCount == 0) {
286N/A fNodeValue[chunk] = null;
286N/A }
286N/A }
286N/A return value;
286N/A }
286N/A
286N/A /**
286N/A * Returns the value of the given node.
286N/A * @param free True to free the value index.
286N/A */
286N/A public String getNodeValue(int nodeIndex, boolean free) {
286N/A
286N/A if (nodeIndex == -1) {
286N/A return null;
286N/A }
286N/A
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A return free ? clearChunkValue(fNodeValue, chunk, index)
286N/A : getChunkValue(fNodeValue, chunk, index);
286N/A
286N/A } // getNodeValue(int,boolean):String
286N/A
286N/A /**
286N/A * Returns the extra info of the given node.
286N/A * Used by AttrImpl to store specified value (1 == true).
286N/A */
286N/A public int getNodeExtra(int nodeIndex) {
286N/A return getNodeExtra(nodeIndex, true);
286N/A }
286N/A
286N/A /**
286N/A * Returns the extra info of the given node.
286N/A * @param free True to free the value index.
286N/A */
286N/A public int getNodeExtra(int nodeIndex, boolean free) {
286N/A
286N/A if (nodeIndex == -1) {
286N/A return -1;
286N/A }
286N/A
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A return free ? clearChunkIndex(fNodeExtra, chunk, index)
286N/A : getChunkIndex(fNodeExtra, chunk, index);
286N/A
286N/A } // getNodeExtra(int,boolean):int
286N/A
286N/A /** Returns the type of the given node. */
286N/A public short getNodeType(int nodeIndex) {
286N/A return getNodeType(nodeIndex, true);
286N/A }
286N/A
286N/A /**
286N/A * Returns the type of the given node.
286N/A * @param free True to free type index.
286N/A */
286N/A public short getNodeType(int nodeIndex, boolean free) {
286N/A
286N/A if (nodeIndex == -1) {
286N/A return -1;
286N/A }
286N/A
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A return free ? (short)clearChunkIndex(fNodeType, chunk, index)
286N/A : (short)getChunkIndex(fNodeType, chunk, index);
286N/A
286N/A } // getNodeType(int):int
286N/A
286N/A /** Returns the attribute value of the given name. */
286N/A public String getAttribute(int elemIndex, String name) {
286N/A if (elemIndex == -1 || name == null) {
286N/A return null;
286N/A }
286N/A int echunk = elemIndex >> CHUNK_SHIFT;
286N/A int eindex = elemIndex & CHUNK_MASK;
286N/A int attrIndex = getChunkIndex(fNodeExtra, echunk, eindex);
286N/A while (attrIndex != -1) {
286N/A int achunk = attrIndex >> CHUNK_SHIFT;
286N/A int aindex = attrIndex & CHUNK_MASK;
286N/A if (getChunkValue(fNodeName, achunk, aindex) == name) {
286N/A return getChunkValue(fNodeValue, achunk, aindex);
286N/A }
286N/A attrIndex = getChunkIndex(fNodePrevSib, achunk, aindex);
286N/A }
286N/A return null;
286N/A }
286N/A
286N/A /** Returns the URI of the given node. */
286N/A public String getNodeURI(int nodeIndex) {
286N/A return getNodeURI(nodeIndex, true);
286N/A }
286N/A
286N/A /**
286N/A * Returns the URI of the given node.
286N/A * @param free True to free URI index.
286N/A */
286N/A public String getNodeURI(int nodeIndex, boolean free) {
286N/A
286N/A if (nodeIndex == -1) {
286N/A return null;
286N/A }
286N/A
286N/A int chunk = nodeIndex >> CHUNK_SHIFT;
286N/A int index = nodeIndex & CHUNK_MASK;
286N/A return free ? clearChunkValue(fNodeURI, chunk, index)
286N/A : getChunkValue(fNodeURI, chunk, index);
286N/A
286N/A } // getNodeURI(int,int):String
286N/A
286N/A // identifier maintenance
286N/A
286N/A /** Registers an identifier name with a specified element node. */
286N/A public void putIdentifier(String name, int elementNodeIndex) {
286N/A
286N/A if (DEBUG_IDS) {
286N/A System.out.println("putIdentifier(" + name + ", "
286N/A + elementNodeIndex + ')' + " // " +
286N/A getChunkValue(fNodeName,
286N/A elementNodeIndex >> CHUNK_SHIFT,
286N/A elementNodeIndex & CHUNK_MASK));
286N/A }
286N/A
286N/A // initialize arrays
286N/A if (fIdName == null) {
286N/A fIdName = new String[64];
286N/A fIdElement = new int[64];
286N/A }
286N/A
286N/A // resize arrays
286N/A if (fIdCount == fIdName.length) {
286N/A String idName[] = new String[fIdCount * 2];
286N/A System.arraycopy(fIdName, 0, idName, 0, fIdCount);
286N/A fIdName = idName;
286N/A
286N/A int idElement[] = new int[idName.length];
286N/A System.arraycopy(fIdElement, 0, idElement, 0, fIdCount);
286N/A fIdElement = idElement;
286N/A }
286N/A
286N/A // store identifier
286N/A fIdName[fIdCount] = name;
286N/A fIdElement[fIdCount] = elementNodeIndex;
286N/A fIdCount++;
286N/A
286N/A } // putIdentifier(String,int)
286N/A
286N/A //
286N/A // DEBUG
286N/A //
286N/A
286N/A /** Prints out the tables. */
286N/A public void print() {
286N/A
286N/A if (DEBUG_PRINT_REF_COUNTS) {
286N/A System.out.print("num\t");
286N/A System.out.print("type\t");
286N/A System.out.print("name\t");
286N/A System.out.print("val\t");
286N/A System.out.print("par\t");
286N/A System.out.print("lch\t");
286N/A System.out.print("psib");
286N/A System.out.println();
286N/A for (int i = 0; i < fNodeType.length; i++) {
286N/A if (fNodeType[i] != null) {
286N/A // separator
286N/A System.out.print("--------");
286N/A System.out.print("--------");
286N/A System.out.print("--------");
286N/A System.out.print("--------");
286N/A System.out.print("--------");
286N/A System.out.print("--------");
286N/A System.out.print("--------");
286N/A System.out.println();
286N/A
286N/A // ref count
286N/A System.out.print(i);
286N/A System.out.print('\t');
286N/A switch (fNodeType[i][CHUNK_SIZE]) {
286N/A case DocumentImpl.ELEMENT_DEFINITION_NODE: { System.out.print("EDef"); break; }
286N/A case Node.DOCUMENT_NODE: { System.out.print("Doc"); break; }
286N/A case Node.DOCUMENT_TYPE_NODE: { System.out.print("DType"); break; }
286N/A case Node.COMMENT_NODE: { System.out.print("Com"); break; }
286N/A case Node.PROCESSING_INSTRUCTION_NODE: { System.out.print("PI"); break; }
286N/A case Node.ELEMENT_NODE: { System.out.print("Elem"); break; }
286N/A case Node.ENTITY_NODE: { System.out.print("Ent"); break; }
286N/A case Node.ENTITY_REFERENCE_NODE: { System.out.print("ERef"); break; }
286N/A case Node.TEXT_NODE: { System.out.print("Text"); break; }
286N/A case Node.ATTRIBUTE_NODE: { System.out.print("Attr"); break; }
286N/A case DeferredNode.TYPE_NODE: { System.out.print("TypeInfo"); break; }
286N/A default: { System.out.print("?"+fNodeType[i][CHUNK_SIZE]); }
286N/A }
286N/A System.out.print('\t');
286N/A System.out.print(fNodeName[i][CHUNK_SIZE]);
286N/A System.out.print('\t');
286N/A System.out.print(fNodeValue[i][CHUNK_SIZE]);
286N/A System.out.print('\t');
286N/A System.out.print(fNodeURI[i][CHUNK_SIZE]);
286N/A System.out.print('\t');
286N/A System.out.print(fNodeParent[i][CHUNK_SIZE]);
286N/A System.out.print('\t');
286N/A System.out.print(fNodeLastChild[i][CHUNK_SIZE]);
286N/A System.out.print('\t');
286N/A System.out.print(fNodePrevSib[i][CHUNK_SIZE]);
286N/A System.out.print('\t');
286N/A System.out.print(fNodeExtra[i][CHUNK_SIZE]);
286N/A System.out.println();
286N/A }
286N/A }
286N/A }
286N/A
286N/A if (DEBUG_PRINT_TABLES) {
286N/A // This assumes that the document is small
286N/A System.out.println("# start table");
286N/A for (int i = 0; i < fNodeCount; i++) {
286N/A int chunk = i >> CHUNK_SHIFT;
286N/A int index = i & CHUNK_MASK;
286N/A if (i % 10 == 0) {
286N/A System.out.print("num\t");
286N/A System.out.print("type\t");
286N/A System.out.print("name\t");
286N/A System.out.print("val\t");
286N/A System.out.print("uri\t");
286N/A System.out.print("par\t");
286N/A System.out.print("lch\t");
286N/A System.out.print("psib\t");
286N/A System.out.print("xtra");
286N/A System.out.println();
286N/A }
286N/A System.out.print(i);
286N/A System.out.print('\t');
286N/A switch (getChunkIndex(fNodeType, chunk, index)) {
286N/A case DocumentImpl.ELEMENT_DEFINITION_NODE: { System.out.print("EDef"); break; }
286N/A case Node.DOCUMENT_NODE: { System.out.print("Doc"); break; }
286N/A case Node.DOCUMENT_TYPE_NODE: { System.out.print("DType"); break; }
286N/A case Node.COMMENT_NODE: { System.out.print("Com"); break; }
286N/A case Node.PROCESSING_INSTRUCTION_NODE: { System.out.print("PI"); break; }
286N/A case Node.ELEMENT_NODE: { System.out.print("Elem"); break; }
286N/A case Node.ENTITY_NODE: { System.out.print("Ent"); break; }
286N/A case Node.ENTITY_REFERENCE_NODE: { System.out.print("ERef"); break; }
286N/A case Node.TEXT_NODE: { System.out.print("Text"); break; }
286N/A case Node.ATTRIBUTE_NODE: { System.out.print("Attr"); break; }
286N/A case DeferredNode.TYPE_NODE: { System.out.print("TypeInfo"); break; }
286N/A default: { System.out.print("?"+getChunkIndex(fNodeType, chunk, index)); }
286N/A }
286N/A System.out.print('\t');
286N/A System.out.print(getChunkValue(fNodeName, chunk, index));
286N/A System.out.print('\t');
286N/A System.out.print(getNodeValue(chunk, index));
286N/A System.out.print('\t');
286N/A System.out.print(getChunkValue(fNodeURI, chunk, index));
286N/A System.out.print('\t');
286N/A System.out.print(getChunkIndex(fNodeParent, chunk, index));
286N/A System.out.print('\t');
286N/A System.out.print(getChunkIndex(fNodeLastChild, chunk, index));
286N/A System.out.print('\t');
286N/A System.out.print(getChunkIndex(fNodePrevSib, chunk, index));
286N/A System.out.print('\t');
286N/A System.out.print(getChunkIndex(fNodeExtra, chunk, index));
286N/A System.out.println();
286N/A }
286N/A System.out.println("# end table");
286N/A }
286N/A
286N/A } // print()
286N/A
286N/A //
286N/A // DeferredNode methods
286N/A //
286N/A
286N/A /** Returns the node index. */
286N/A public int getNodeIndex() {
286N/A return 0;
286N/A }
286N/A
286N/A //
286N/A // Protected methods
286N/A //
286N/A
286N/A /** Synchronizes the node's data. */
286N/A protected void synchronizeData() {
286N/A
286N/A // no need to sync in the future
286N/A needsSyncData(false);
286N/A
286N/A // fluff up enough nodes to fill identifiers hash
286N/A if (fIdElement != null) {
286N/A
286N/A // REVISIT: There has to be a more efficient way of
286N/A // doing this. But keep in mind that the
286N/A // tree can have been altered and re-ordered
286N/A // before all of the element nodes with ID
286N/A // attributes have been registered. For now
286N/A // this is reasonable and safe. -Ac
286N/A
286N/A IntVector path = new IntVector();
286N/A for (int i = 0; i < fIdCount; i++) {
286N/A
286N/A // ignore if it's already been registered
286N/A int elementNodeIndex = fIdElement[i];
286N/A String idName = fIdName[i];
286N/A if (idName == null) {
286N/A continue;
286N/A }
286N/A
286N/A // find path from this element to the root
286N/A path.removeAllElements();
286N/A int index = elementNodeIndex;
286N/A do {
286N/A path.addElement(index);
286N/A int pchunk = index >> CHUNK_SHIFT;
286N/A int pindex = index & CHUNK_MASK;
286N/A index = getChunkIndex(fNodeParent, pchunk, pindex);
286N/A } while (index != -1);
286N/A
286N/A // Traverse path (backwards), fluffing the elements
286N/A // along the way. When this loop finishes, "place"
286N/A // will contain the reference to the element node
286N/A // we're interested in. -Ac
286N/A Node place = this;
286N/A for (int j = path.size() - 2; j >= 0; j--) {
286N/A index = path.elementAt(j);
286N/A Node child = place.getLastChild();
286N/A while (child != null) {
286N/A if (child instanceof DeferredNode) {
286N/A int nodeIndex =
286N/A ((DeferredNode)child).getNodeIndex();
286N/A if (nodeIndex == index) {
286N/A place = child;
286N/A break;
286N/A }
286N/A }
286N/A child = child.getPreviousSibling();
286N/A }
286N/A }
286N/A
286N/A // register the element
286N/A Element element = (Element)place;
286N/A putIdentifier0(idName, element);
286N/A fIdName[i] = null;
286N/A
286N/A // see if there are more IDs on this element
286N/A while (i + 1 < fIdCount &&
286N/A fIdElement[i + 1] == elementNodeIndex) {
286N/A idName = fIdName[++i];
286N/A if (idName == null) {
286N/A continue;
286N/A }
286N/A putIdentifier0(idName, element);
286N/A }
286N/A }
286N/A
286N/A } // if identifiers
286N/A
286N/A } // synchronizeData()
286N/A
286N/A /**
286N/A * Synchronizes the node's children with the internal structure.
286N/A * Fluffing the children at once solves a lot of work to keep
286N/A * the two structures in sync. The problem gets worse when
286N/A * editing the tree -- this makes it a lot easier.
286N/A */
286N/A protected void synchronizeChildren() {
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A /*
286N/A * when we have elements with IDs this method is being recursively
286N/A * called from synchronizeData, in which case we've already gone
286N/A * through the following and we can now simply stop here.
286N/A */
286N/A if (!needsSyncChildren()) {
286N/A return;
286N/A }
286N/A }
286N/A
286N/A // we don't want to generate any event for this so turn them off
286N/A boolean orig = mutationEvents;
286N/A mutationEvents = false;
286N/A
286N/A // no need to sync in the future
286N/A needsSyncChildren(false);
286N/A
286N/A getNodeType(0);
286N/A
286N/A // create children and link them as siblings
286N/A ChildNode first = null;
286N/A ChildNode last = null;
286N/A for (int index = getLastChild(0);
286N/A index != -1;
286N/A index = getPrevSibling(index)) {
286N/A
286N/A ChildNode node = (ChildNode)getNodeObject(index);
286N/A if (last == null) {
286N/A last = node;
286N/A }
286N/A else {
286N/A first.previousSibling = node;
286N/A }
286N/A node.ownerNode = this;
286N/A node.isOwned(true);
286N/A node.nextSibling = first;
286N/A first = node;
286N/A
286N/A // save doctype and document type
286N/A int type = node.getNodeType();
286N/A if (type == Node.ELEMENT_NODE) {
286N/A docElement = (ElementImpl)node;
286N/A }
286N/A else if (type == Node.DOCUMENT_TYPE_NODE) {
286N/A docType = (DocumentTypeImpl)node;
286N/A }
286N/A }
286N/A
286N/A if (first != null) {
286N/A firstChild = first;
286N/A first.isFirstChild(true);
286N/A lastChild(last);
286N/A }
286N/A
286N/A // set mutation events flag back to its original value
286N/A mutationEvents = orig;
286N/A
286N/A } // synchronizeChildren()
286N/A
286N/A /**
286N/A * Synchronizes the node's children with the internal structure.
286N/A * Fluffing the children at once solves a lot of work to keep
286N/A * the two structures in sync. The problem gets worse when
286N/A * editing the tree -- this makes it a lot easier.
286N/A * This is not directly used in this class but this method is
286N/A * here so that it can be shared by all deferred subclasses of AttrImpl.
286N/A */
286N/A protected final void synchronizeChildren(AttrImpl a, int nodeIndex) {
286N/A
286N/A // we don't want to generate any event for this so turn them off
286N/A boolean orig = getMutationEvents();
286N/A setMutationEvents(false);
286N/A
286N/A // no need to sync in the future
286N/A a.needsSyncChildren(false);
286N/A
286N/A // create children and link them as siblings or simply store the value
286N/A // as a String if all we have is one piece of text
286N/A int last = getLastChild(nodeIndex);
286N/A int prev = getPrevSibling(last);
286N/A if (prev == -1) {
286N/A a.value = getNodeValueString(nodeIndex);
286N/A a.hasStringValue(true);
286N/A }
286N/A else {
286N/A ChildNode firstNode = null;
286N/A ChildNode lastNode = null;
286N/A for (int index = last; index != -1;
286N/A index = getPrevSibling(index)) {
286N/A
286N/A ChildNode node = (ChildNode) getNodeObject(index);
286N/A if (lastNode == null) {
286N/A lastNode = node;
286N/A }
286N/A else {
286N/A firstNode.previousSibling = node;
286N/A }
286N/A node.ownerNode = a;
286N/A node.isOwned(true);
286N/A node.nextSibling = firstNode;
286N/A firstNode = node;
286N/A }
286N/A if (lastNode != null) {
286N/A a.value = firstNode; // firstChild = firstNode
286N/A firstNode.isFirstChild(true);
286N/A a.lastChild(lastNode);
286N/A }
286N/A a.hasStringValue(false);
286N/A }
286N/A
286N/A // set mutation events flag back to its original value
286N/A setMutationEvents(orig);
286N/A
286N/A } // synchronizeChildren(AttrImpl,int):void
286N/A
286N/A
286N/A /**
286N/A * Synchronizes the node's children with the internal structure.
286N/A * Fluffing the children at once solves a lot of work to keep
286N/A * the two structures in sync. The problem gets worse when
286N/A * editing the tree -- this makes it a lot easier.
286N/A * This is not directly used in this class but this method is
286N/A * here so that it can be shared by all deferred subclasses of ParentNode.
286N/A */
286N/A protected final void synchronizeChildren(ParentNode p, int nodeIndex) {
286N/A
286N/A // we don't want to generate any event for this so turn them off
286N/A boolean orig = getMutationEvents();
286N/A setMutationEvents(false);
286N/A
286N/A // no need to sync in the future
286N/A p.needsSyncChildren(false);
286N/A
286N/A // create children and link them as siblings
286N/A ChildNode firstNode = null;
286N/A ChildNode lastNode = null;
286N/A for (int index = getLastChild(nodeIndex);
286N/A index != -1;
286N/A index = getPrevSibling(index)) {
286N/A
286N/A ChildNode node = (ChildNode) getNodeObject(index);
286N/A if (lastNode == null) {
286N/A lastNode = node;
286N/A }
286N/A else {
286N/A firstNode.previousSibling = node;
286N/A }
286N/A node.ownerNode = p;
286N/A node.isOwned(true);
286N/A node.nextSibling = firstNode;
286N/A firstNode = node;
286N/A }
286N/A if (lastNode != null) {
286N/A p.firstChild = firstNode;
286N/A firstNode.isFirstChild(true);
286N/A p.lastChild(lastNode);
286N/A }
286N/A
286N/A // set mutation events flag back to its original value
286N/A setMutationEvents(orig);
286N/A
286N/A } // synchronizeChildren(ParentNode,int):void
286N/A
286N/A // utility methods
286N/A
286N/A /** Ensures that the internal tables are large enough. */
286N/A protected void ensureCapacity(int chunk) {
286N/A if (fNodeType == null) {
286N/A // create buffers
286N/A fNodeType = new int[INITIAL_CHUNK_COUNT][];
286N/A fNodeName = new Object[INITIAL_CHUNK_COUNT][];
286N/A fNodeValue = new Object[INITIAL_CHUNK_COUNT][];
286N/A fNodeParent = new int[INITIAL_CHUNK_COUNT][];
286N/A fNodeLastChild = new int[INITIAL_CHUNK_COUNT][];
286N/A fNodePrevSib = new int[INITIAL_CHUNK_COUNT][];
286N/A fNodeURI = new Object[INITIAL_CHUNK_COUNT][];
286N/A fNodeExtra = new int[INITIAL_CHUNK_COUNT][];
286N/A }
286N/A else if (fNodeType.length <= chunk) {
286N/A // resize the tables
286N/A int newsize = chunk * 2;
286N/A
286N/A int[][] newArray = new int[newsize][];
286N/A System.arraycopy(fNodeType, 0, newArray, 0, chunk);
286N/A fNodeType = newArray;
286N/A
286N/A Object[][] newStrArray = new Object[newsize][];
286N/A System.arraycopy(fNodeName, 0, newStrArray, 0, chunk);
286N/A fNodeName = newStrArray;
286N/A
286N/A newStrArray = new Object[newsize][];
286N/A System.arraycopy(fNodeValue, 0, newStrArray, 0, chunk);
286N/A fNodeValue = newStrArray;
286N/A
286N/A newArray = new int[newsize][];
286N/A System.arraycopy(fNodeParent, 0, newArray, 0, chunk);
286N/A fNodeParent = newArray;
286N/A
286N/A newArray = new int[newsize][];
286N/A System.arraycopy(fNodeLastChild, 0, newArray, 0, chunk);
286N/A fNodeLastChild = newArray;
286N/A
286N/A newArray = new int[newsize][];
286N/A System.arraycopy(fNodePrevSib, 0, newArray, 0, chunk);
286N/A fNodePrevSib = newArray;
286N/A
286N/A newStrArray = new Object[newsize][];
286N/A System.arraycopy(fNodeURI, 0, newStrArray, 0, chunk);
286N/A fNodeURI = newStrArray;
286N/A
286N/A newArray = new int[newsize][];
286N/A System.arraycopy(fNodeExtra, 0, newArray, 0, chunk);
286N/A fNodeExtra = newArray;
286N/A }
286N/A else if (fNodeType[chunk] != null) {
286N/A // Done - there's sufficient capacity
286N/A return;
286N/A }
286N/A
286N/A // create new chunks
286N/A createChunk(fNodeType, chunk);
286N/A createChunk(fNodeName, chunk);
286N/A createChunk(fNodeValue, chunk);
286N/A createChunk(fNodeParent, chunk);
286N/A createChunk(fNodeLastChild, chunk);
286N/A createChunk(fNodePrevSib, chunk);
286N/A createChunk(fNodeURI, chunk);
286N/A createChunk(fNodeExtra, chunk);
286N/A
286N/A // Done
286N/A return;
286N/A
286N/A } // ensureCapacity(int,int)
286N/A
286N/A /** Creates a node of the specified type. */
286N/A protected int createNode(short nodeType) {
286N/A // ensure tables are large enough
286N/A int chunk = fNodeCount >> CHUNK_SHIFT;
286N/A int index = fNodeCount & CHUNK_MASK;
286N/A ensureCapacity(chunk);
286N/A
286N/A // initialize node
286N/A setChunkIndex(fNodeType, nodeType, chunk, index);
286N/A
286N/A // return node index number
286N/A return fNodeCount++;
286N/A
286N/A } // createNode(short):int
286N/A
286N/A /**
286N/A * Performs a binary search for a target value in an array of
286N/A * values. The array of values must be in ascending sorted order
286N/A * before calling this method and all array values must be
286N/A * non-negative.
286N/A *
286N/A * @param values The array of values to search.
286N/A * @param start The starting offset of the search.
286N/A * @param end The ending offset of the search.
286N/A * @param target The target value.
286N/A *
286N/A * @return This function will return the <i>first</i> occurrence
286N/A * of the target value, or -1 if the target value cannot
286N/A * be found.
286N/A */
286N/A protected static int binarySearch(final int values[],
286N/A int start, int end, int target) {
286N/A
286N/A if (DEBUG_IDS) {
286N/A System.out.println("binarySearch(), target: "+target);
286N/A }
286N/A
286N/A // look for target value
286N/A while (start <= end) {
286N/A
286N/A // is this the one we're looking for?
286N/A int middle = (start + end) >>> 1;
286N/A int value = values[middle];
286N/A if (DEBUG_IDS) {
286N/A System.out.print(" value: "+value+", target: "+target+" // ");
286N/A print(values, start, end, middle, target);
286N/A }
286N/A if (value == target) {
286N/A while (middle > 0 && values[middle - 1] == target) {
286N/A middle--;
286N/A }
286N/A if (DEBUG_IDS) {
286N/A System.out.println("FOUND AT "+middle);
286N/A }
286N/A return middle;
286N/A }
286N/A
286N/A // is this point higher or lower?
286N/A if (value > target) {
286N/A end = middle - 1;
286N/A }
286N/A else {
286N/A start = middle + 1;
286N/A }
286N/A
286N/A } // while
286N/A
286N/A // not found
286N/A if (DEBUG_IDS) {
286N/A System.out.println("NOT FOUND!");
286N/A }
286N/A return -1;
286N/A
286N/A } // binarySearch(int[],int,int,int):int
286N/A
286N/A //
286N/A // Private methods
286N/A //
286N/A private static final int[] INIT_ARRAY = new int[CHUNK_SIZE + 1];
286N/A static {
286N/A for (int i = 0; i < CHUNK_SIZE; i++) {
286N/A INIT_ARRAY[i] = -1;
286N/A }
286N/A }
286N/A /** Creates the specified chunk in the given array of chunks. */
286N/A private final void createChunk(int data[][], int chunk) {
286N/A data[chunk] = new int[CHUNK_SIZE + 1];
286N/A System.arraycopy(INIT_ARRAY, 0, data[chunk], 0, CHUNK_SIZE);
286N/A }
286N/A
286N/A static final class RefCount {
286N/A int fCount;
286N/A }
286N/A
286N/A private final void createChunk(Object data[][], int chunk) {
286N/A data[chunk] = new Object[CHUNK_SIZE + 1];
286N/A data[chunk][CHUNK_SIZE] = new RefCount();
286N/A }
286N/A
286N/A /**
286N/A * Sets the specified value in the given of data at the chunk and index.
286N/A *
286N/A * @return Returns the old value.
286N/A */
286N/A private final int setChunkIndex(int data[][], int value,
286N/A int chunk, int index) {
286N/A if (value == -1) {
286N/A return clearChunkIndex(data, chunk, index);
286N/A }
286N/A int [] dataChunk = data[chunk];
286N/A // Re-create chunk if it was deleted.
286N/A if (dataChunk == null) {
286N/A createChunk(data, chunk);
286N/A dataChunk = data[chunk];
286N/A }
286N/A int ovalue = dataChunk[index];
286N/A if (ovalue == -1) {
286N/A dataChunk[CHUNK_SIZE]++;
286N/A }
286N/A dataChunk[index] = value;
286N/A return ovalue;
286N/A }
286N/A private final String setChunkValue(Object data[][], Object value,
286N/A int chunk, int index) {
286N/A if (value == null) {
286N/A return clearChunkValue(data, chunk, index);
286N/A }
286N/A Object [] dataChunk = data[chunk];
286N/A // Re-create chunk if it was deleted.
286N/A if (dataChunk == null) {
286N/A createChunk(data, chunk);
286N/A dataChunk = data[chunk];
286N/A }
286N/A String ovalue = (String) dataChunk[index];
286N/A if (ovalue == null) {
286N/A RefCount c = (RefCount) dataChunk[CHUNK_SIZE];
286N/A c.fCount++;
286N/A }
286N/A dataChunk[index] = value;
286N/A return ovalue;
286N/A }
286N/A
286N/A /**
286N/A * Returns the specified value in the given data at the chunk and index.
286N/A */
286N/A private final int getChunkIndex(int data[][], int chunk, int index) {
286N/A return data[chunk] != null ? data[chunk][index] : -1;
286N/A }
286N/A private final String getChunkValue(Object data[][], int chunk, int index) {
286N/A return data[chunk] != null ? (String) data[chunk][index] : null;
286N/A }
286N/A private final String getNodeValue(int chunk, int index) {
286N/A Object data = fNodeValue[chunk][index];
286N/A if (data == null){
286N/A return null;
286N/A }
286N/A else if (data instanceof String){
286N/A return (String)data;
286N/A }
286N/A else {
286N/A // type information
286N/A return data.toString();
286N/A }
286N/A }
286N/A
286N/A
286N/A /**
286N/A * Clears the specified value in the given data at the chunk and index.
286N/A * Note that this method will clear the given chunk if the reference
286N/A * count becomes zero.
286N/A *
286N/A * @return Returns the old value.
286N/A */
286N/A private final int clearChunkIndex(int data[][], int chunk, int index) {
286N/A int value = data[chunk] != null ? data[chunk][index] : -1;
286N/A if (value != -1) {
286N/A data[chunk][CHUNK_SIZE]--;
286N/A data[chunk][index] = -1;
286N/A if (data[chunk][CHUNK_SIZE] == 0) {
286N/A data[chunk] = null;
286N/A }
286N/A }
286N/A return value;
286N/A }
286N/A private final String clearChunkValue(Object data[][],
286N/A int chunk, int index) {
286N/A String value = data[chunk] != null ? (String)data[chunk][index] : null;
286N/A if (value != null) {
286N/A data[chunk][index] = null;
286N/A RefCount c = (RefCount) data[chunk][CHUNK_SIZE];
286N/A c.fCount--;
286N/A if (c.fCount == 0) {
286N/A data[chunk] = null;
286N/A }
286N/A }
286N/A return value;
286N/A }
286N/A
286N/A /**
286N/A * This version of putIdentifier is needed to avoid fluffing
286N/A * all of the paths to ID attributes when a node object is
286N/A * created that contains an ID attribute.
286N/A */
286N/A private final void putIdentifier0(String idName, Element element) {
286N/A
286N/A if (DEBUG_IDS) {
286N/A System.out.println("putIdentifier0("+
286N/A idName+", "+
286N/A element+')');
286N/A }
286N/A
286N/A // create hashtable
286N/A if (identifiers == null) {
286N/A identifiers = new java.util.Hashtable();
286N/A }
286N/A
286N/A // save ID and its associated element
286N/A identifiers.put(idName, element);
286N/A
286N/A } // putIdentifier0(String,Element)
286N/A
286N/A /** Prints the ID array. */
286N/A private static void print(int values[], int start, int end,
286N/A int middle, int target) {
286N/A
286N/A if (DEBUG_IDS) {
286N/A System.out.print(start);
286N/A System.out.print(" [");
286N/A for (int i = start; i < end; i++) {
286N/A if (middle == i) {
286N/A System.out.print("!");
286N/A }
286N/A System.out.print(values[i]);
286N/A if (values[i] == target) {
286N/A System.out.print("*");
286N/A }
286N/A if (i < end - 1) {
286N/A System.out.print(" ");
286N/A }
286N/A }
286N/A System.out.println("] "+end);
286N/A }
286N/A
286N/A } // print(int[],int,int,int,int)
286N/A
286N/A //
286N/A // Classes
286N/A //
286N/A
286N/A /**
286N/A * A simple integer vector.
286N/A */
286N/A static final class IntVector {
286N/A
286N/A //
286N/A // Data
286N/A //
286N/A
286N/A /** Data. */
286N/A private int data[];
286N/A
286N/A /** Size. */
286N/A private int size;
286N/A
286N/A //
286N/A // Public methods
286N/A //
286N/A
286N/A /** Returns the length of this vector. */
286N/A public int size() {
286N/A return size;
286N/A }
286N/A
286N/A /** Returns the element at the specified index. */
286N/A public int elementAt(int index) {
286N/A return data[index];
286N/A }
286N/A
286N/A /** Appends an element to the end of the vector. */
286N/A public void addElement(int element) {
286N/A ensureCapacity(size + 1);
286N/A data[size++] = element;
286N/A }
286N/A
286N/A /** Clears the vector. */
286N/A public void removeAllElements() {
286N/A size = 0;
286N/A }
286N/A
286N/A //
286N/A // Private methods
286N/A //
286N/A
286N/A /** Makes sure that there is enough storage. */
286N/A private void ensureCapacity(int newsize) {
286N/A
286N/A if (data == null) {
286N/A data = new int[newsize + 15];
286N/A }
286N/A else if (newsize > data.length) {
286N/A int newdata[] = new int[newsize + 15];
286N/A System.arraycopy(data, 0, newdata, 0, data.length);
286N/A data = newdata;
286N/A }
286N/A
286N/A } // ensureCapacity(int)
286N/A
286N/A } // class IntVector
286N/A
286N/A} // class DeferredDocumentImpl