0001: /*
0002: * The Apache Software License, Version 1.1
0003: *
0004: *
0005: * Copyright (c) 1999-2001 The Apache Software Foundation. All rights
0006: * reserved.
0007: *
0008: * Redistribution and use in source and binary forms, with or without
0009: * modification, are permitted provided that the following conditions
0010: * are met:
0011: *
0012: * 1. Redistributions of source code must retain the above copyright
0013: * notice, this list of conditions and the following disclaimer.
0014: *
0015: * 2. Redistributions in binary form must reproduce the above copyright
0016: * notice, this list of conditions and the following disclaimer in
0017: * the documentation and/or other materials provided with the
0018: * distribution.
0019: *
0020: * 3. The end-user documentation included with the redistribution,
0021: * if any, must include the following acknowledgment:
0022: * "This product includes software developed by the
0023: * Apache Software Foundation (http://www.apache.org/)."
0024: * Alternately, this acknowledgment may appear in the software itself,
0025: * if and wherever such third-party acknowledgments normally appear.
0026: *
0027: * 4. The names "Xerces" and "Apache Software Foundation" must
0028: * not be used to endorse or promote products derived from this
0029: * software without prior written permission. For written
0030: * permission, please contact apache@apache.org.
0031: *
0032: * 5. Products derived from this software may not be called "Apache",
0033: * nor may "Apache" appear in their name, without prior written
0034: * permission of the Apache Software Foundation.
0035: *
0036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0047: * SUCH DAMAGE.
0048: * ====================================================================
0049: *
0050: * This software consists of voluntary contributions made by many
0051: * individuals on behalf of the Apache Software Foundation and was
0052: * originally based on software copyright (c) 1999, International
0053: * Business Machines, Inc., http://www.apache.org. For more
0054: * information on the Apache Software Foundation, please see
0055: * <http://www.apache.org/>.
0056: */
0057:
0058: package org.apache.xerces.dom;
0059:
0060: import org.apache.xerces.framework.XMLAttrList;
0061: import org.apache.xerces.utils.StringPool;
0062:
0063: import org.w3c.dom.Element;
0064: import org.w3c.dom.Node;
0065: import java.util.Vector;
0066:
0067: /**
0068: * The Document interface represents the entire HTML or XML document.
0069: * Conceptually, it is the root of the document tree, and provides the
0070: * primary access to the document's data.
0071: * <P>
0072: * Since elements, text nodes, comments, processing instructions,
0073: * etc. cannot exist outside the context of a Document, the Document
0074: * interface also contains the factory methods needed to create these
0075: * objects. The Node objects created have a ownerDocument attribute
0076: * which associates them with the Document within whose context they
0077: * were created.
0078: *
0079: * @version
0080: * @since PR-DOM-Level-1-19980818.
0081: */
0082: public class DeferredDocumentImpl extends DocumentImpl implements
0083: DeferredNode {
0084:
0085: //
0086: // Constants
0087: //
0088:
0089: /** Serialization version. */
0090: static final long serialVersionUID = 5186323580749626857L;
0091:
0092: // debugging
0093:
0094: /** To include code for printing the ref count tables. */
0095: private static final boolean DEBUG_PRINT_REF_COUNTS = false;
0096:
0097: /** To include code for printing the internal tables. */
0098: private static final boolean DEBUG_PRINT_TABLES = false;
0099:
0100: /** To debug identifiers set to true and recompile. */
0101: private static final boolean DEBUG_IDS = false;
0102:
0103: // protected
0104:
0105: /** Chunk shift. */
0106: protected static final int CHUNK_SHIFT = 11; // 2^11 = 2k
0107:
0108: /** Chunk size. */
0109: protected static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
0110:
0111: /** Chunk mask. */
0112: protected static final int CHUNK_MASK = CHUNK_SIZE - 1;
0113:
0114: /** Initial chunk size. */
0115: protected static final int INITIAL_CHUNK_COUNT = (1 << (16 - CHUNK_SHIFT)); // 2^16 = 64k
0116:
0117: //
0118: // Data
0119: //
0120:
0121: // lazy-eval information
0122:
0123: /** Node count. */
0124: protected transient int fNodeCount = 0;
0125:
0126: /** Node types. */
0127: protected transient int fNodeType[][];
0128:
0129: /** Node names. */
0130: protected transient int fNodeName[][];
0131:
0132: /** Node values. */
0133: protected transient int fNodeValue[][];
0134:
0135: /** Node parents. */
0136: protected transient int fNodeParent[][];
0137:
0138: /** Node first children. */
0139: protected transient int fNodeLastChild[][];
0140:
0141: /** Node prev siblings. */
0142: protected transient int fNodePrevSib[][];
0143:
0144: /** Node namespace URI. */
0145: protected transient int fNodeURI[][];
0146:
0147: /** Identifier count. */
0148: protected transient int fIdCount;
0149:
0150: /** Identifier name indexes. */
0151: protected transient int fIdName[];
0152:
0153: /** Identifier element indexes. */
0154: protected transient int fIdElement[];
0155:
0156: /** String pool cache. */
0157: protected transient StringPool fStringPool;
0158:
0159: /** DOM2: For namespace support in the deferred case.
0160: */
0161: // Implementation Note: The deferred element and attribute must know how to
0162: // interpret the int representing the qname.
0163: protected boolean fNamespacesEnabled = false;
0164:
0165: private final StringBuffer fBufferStr = new StringBuffer();
0166: private final Vector fStrChunks = new Vector();
0167:
0168: //
0169: // Constructors
0170: //
0171:
0172: /**
0173: * NON-DOM: Actually creating a Document is outside the DOM's spec,
0174: * since it has to operate in terms of a particular implementation.
0175: */
0176: public DeferredDocumentImpl(StringPool stringPool) {
0177: this (stringPool, false);
0178: } // <init>(ParserState)
0179:
0180: /**
0181: * NON-DOM: Actually creating a Document is outside the DOM's spec,
0182: * since it has to operate in terms of a particular implementation.
0183: */
0184: public DeferredDocumentImpl(StringPool stringPool,
0185: boolean namespacesEnabled) {
0186: this (stringPool, namespacesEnabled, false);
0187: } // <init>(ParserState,boolean)
0188:
0189: /** Experimental constructor. */
0190: public DeferredDocumentImpl(StringPool stringPool,
0191: boolean namespaces, boolean grammarAccess) {
0192: super (grammarAccess);
0193:
0194: fStringPool = stringPool;
0195:
0196: needsSyncData(true);
0197: needsSyncChildren(true);
0198:
0199: fNamespacesEnabled = namespaces;
0200:
0201: } // <init>(StringPool,boolean,boolean)
0202:
0203: //
0204: // Public methods
0205: //
0206:
0207: /** Returns the cached parser.getNamespaces() value.*/
0208: boolean getNamespacesEnabled() {
0209: return fNamespacesEnabled;
0210: }
0211:
0212: // internal factory methods
0213:
0214: /** Creates a document node in the table. */
0215: public int createDocument() {
0216: int nodeIndex = createNode(Node.DOCUMENT_NODE);
0217: return nodeIndex;
0218: }
0219:
0220: /** Creates a doctype. */
0221: public int createDocumentType(int rootElementNameIndex,
0222: int publicId, int systemId) {
0223:
0224: // create node
0225: int nodeIndex = createNode(Node.DOCUMENT_TYPE_NODE);
0226: int chunk = nodeIndex >> CHUNK_SHIFT;
0227: int index = nodeIndex & CHUNK_MASK;
0228:
0229: // added for DOM2: createDoctype factory method includes
0230: // name, publicID, systemID
0231:
0232: // create extra data node
0233: int extraDataIndex = createNode((short) 0); // node type unimportant
0234: int echunk = extraDataIndex >> CHUNK_SHIFT;
0235: int eindex = extraDataIndex & CHUNK_MASK;
0236:
0237: // save name, public id, system id
0238: setChunkIndex(fNodeName, rootElementNameIndex, chunk, index);
0239: setChunkIndex(fNodeValue, extraDataIndex, chunk, index);
0240: setChunkIndex(fNodeName, publicId, echunk, eindex);
0241: setChunkIndex(fNodeValue, systemId, echunk, eindex);
0242:
0243: // return node index
0244: return nodeIndex;
0245:
0246: } // createDocumentType(int,int,int):int
0247:
0248: public void setInternalSubset(int doctypeIndex, int subsetIndex) {
0249: int chunk = doctypeIndex >> CHUNK_SHIFT;
0250: int index = doctypeIndex & CHUNK_MASK;
0251: int extraDataIndex = fNodeValue[chunk][index];
0252: int echunk = extraDataIndex >> CHUNK_SHIFT;
0253: int eindex = extraDataIndex & CHUNK_MASK;
0254: setChunkIndex(fNodeLastChild, subsetIndex, echunk, eindex);
0255: }
0256:
0257: /** Creates a notation in the table. */
0258: public int createNotation(int notationName, int publicId,
0259: int systemId) throws Exception {
0260:
0261: // create node
0262: int nodeIndex = createNode(Node.NOTATION_NODE);
0263: int chunk = nodeIndex >> CHUNK_SHIFT;
0264: int index = nodeIndex & CHUNK_MASK;
0265:
0266: // create extra data node
0267: int extraDataIndex = createNode((short) 0); // node type unimportant
0268: int echunk = extraDataIndex >> CHUNK_SHIFT;
0269: int eindex = extraDataIndex & CHUNK_MASK;
0270:
0271: // save name, public id, system id, and notation name
0272: setChunkIndex(fNodeName, notationName, chunk, index);
0273: setChunkIndex(fNodeValue, extraDataIndex, chunk, index);
0274: setChunkIndex(fNodeName, publicId, echunk, eindex);
0275: setChunkIndex(fNodeValue, systemId, echunk, eindex);
0276:
0277: // return node index
0278: return nodeIndex;
0279:
0280: } // createNotation(int,int,int):int
0281:
0282: /** Creates an entity in the table. */
0283: public int createEntity(int entityName, int publicId, int systemId,
0284: int notationName) throws Exception {
0285: // create node
0286: int nodeIndex = createNode(Node.ENTITY_NODE);
0287: int chunk = nodeIndex >> CHUNK_SHIFT;
0288: int index = nodeIndex & CHUNK_MASK;
0289:
0290: // create extra data node
0291: int extraDataIndex = createNode((short) 0); // node type unimportant
0292: int echunk = extraDataIndex >> CHUNK_SHIFT;
0293: int eindex = extraDataIndex & CHUNK_MASK;
0294:
0295: // create extra data node DOM Level 3 - el
0296: int extraDataIndex2 = createNode((short) 0); // node type unimportant
0297: int echunk2 = extraDataIndex2 >> CHUNK_SHIFT;
0298: int eindex2 = extraDataIndex2 & CHUNK_MASK;
0299:
0300: // save name, public id, system id, and notation name
0301: setChunkIndex(fNodeName, entityName, chunk, index);
0302: setChunkIndex(fNodeValue, extraDataIndex, chunk, index);
0303: setChunkIndex(fNodeLastChild, notationName, echunk, eindex);
0304: setChunkIndex(fNodeName, publicId, echunk, eindex);
0305: setChunkIndex(fNodeValue, extraDataIndex2, echunk, eindex);
0306: setChunkIndex(fNodeName, systemId, echunk2, eindex2);
0307:
0308: // initialize encoding and verison for DOM Level 3 - el
0309: setChunkIndex(fNodeValue, -1, echunk2, eindex2);
0310: setChunkIndex(fNodeLastChild, -1, echunk2, eindex2);
0311:
0312: // return node index
0313: return nodeIndex;
0314:
0315: } // createEntity(int,int,int,int):int
0316:
0317: // DOM Level 3 - el
0318: // setting encoding and version
0319: public void setEntityInfo(int currentEntityDecl, int versionIndex,
0320: int encodingIndex) {
0321: int eNodeIndex = getNodeValue(getNodeValue(currentEntityDecl,
0322: false), false);
0323: if (eNodeIndex != -1) {
0324: int echunk = eNodeIndex >> CHUNK_SHIFT;
0325: int eindex = eNodeIndex & CHUNK_MASK;
0326: setChunkIndex(fNodeValue, versionIndex, echunk, eindex);
0327: setChunkIndex(fNodeLastChild, encodingIndex, echunk, eindex);
0328: }
0329: }
0330:
0331: /** Creates an entity reference node in the table. */
0332: public int createEntityReference(int nameIndex) throws Exception {
0333:
0334: // create node
0335: int nodeIndex = createNode(Node.ENTITY_REFERENCE_NODE);
0336: int chunk = nodeIndex >> CHUNK_SHIFT;
0337: int index = nodeIndex & CHUNK_MASK;
0338: setChunkIndex(fNodeName, nameIndex, chunk, index);
0339:
0340: // return node index
0341: return nodeIndex;
0342:
0343: } // createEntityReference(int):int
0344:
0345: /** Creates an element node in the table. */
0346: public int createElement(int elementNameIndex,
0347: XMLAttrList attrList, int attrListIndex) {
0348: return createElement(elementNameIndex, -1, attrList,
0349: attrListIndex);
0350: }
0351:
0352: /** Creates an element node with a URI in the table. */
0353: public int createElement(int elementNameIndex, int elementURIIndex,
0354: XMLAttrList attrList, int attrListIndex) {
0355:
0356: // create node
0357: int elementNodeIndex = createNode(Node.ELEMENT_NODE);
0358: int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
0359: int elementIndex = elementNodeIndex & CHUNK_MASK;
0360: setChunkIndex(fNodeName, elementNameIndex, elementChunk,
0361: elementIndex);
0362: setChunkIndex(fNodeURI, elementURIIndex, elementChunk,
0363: elementIndex);
0364:
0365: // create attributes
0366: if (attrListIndex != -1) {
0367: int first = attrList.getFirstAttr(attrListIndex);
0368: int lastAttrNodeIndex = -1;
0369: int lastAttrChunk = -1;
0370: int lastAttrIndex = -1;
0371: for (int index = first; index != -1; index = attrList
0372: .getNextAttr(index)) {
0373:
0374: // create attribute
0375: int attrNodeIndex = createAttribute(attrList
0376: .getAttrName(index),
0377: attrList.getAttrURI(index), attrList
0378: .getAttValue(index), attrList
0379: .isSpecified(index));
0380: int attrChunk = attrNodeIndex >> CHUNK_SHIFT;
0381: int attrIndex = attrNodeIndex & CHUNK_MASK;
0382: setChunkIndex(fNodeParent, elementNodeIndex, attrChunk,
0383: attrIndex);
0384:
0385: // add links
0386: if (index == first) {
0387: setChunkIndex(fNodeValue, attrNodeIndex,
0388: elementChunk, elementIndex);
0389: } else {
0390: setChunkIndex(fNodePrevSib, attrNodeIndex,
0391: lastAttrChunk, lastAttrIndex);
0392: }
0393:
0394: // save last chunk and index
0395: lastAttrNodeIndex = attrNodeIndex;
0396: lastAttrChunk = attrChunk;
0397: lastAttrIndex = attrIndex;
0398: }
0399: }
0400:
0401: // return node index
0402: return elementNodeIndex;
0403:
0404: } // createElement(int,XMLAttrList,int):int
0405:
0406: /** Creates an attribute in the table. */
0407: public int createAttribute(int attrNameIndex, int attrValueIndex,
0408: boolean specified) {
0409: return createAttribute(attrNameIndex, -1, attrValueIndex,
0410: specified);
0411: }
0412:
0413: /** Creates an attribute with a URI in the table. */
0414: public int createAttribute(int attrNameIndex, int attrURIIndex,
0415: int attrValueIndex, boolean specified) {
0416:
0417: // create node
0418: int nodeIndex = createNode(NodeImpl.ATTRIBUTE_NODE);
0419: int chunk = nodeIndex >> CHUNK_SHIFT;
0420: int index = nodeIndex & CHUNK_MASK;
0421: setChunkIndex(fNodeName, attrNameIndex, chunk, index);
0422: setChunkIndex(fNodeURI, attrURIIndex, chunk, index);
0423: setChunkIndex(fNodeValue, specified ? 1 : 0, chunk, index);
0424:
0425: // append value as text node
0426: int textNodeIndex = createTextNode(attrValueIndex, false);
0427: appendChild(nodeIndex, textNodeIndex);
0428:
0429: // return node index
0430: return nodeIndex;
0431:
0432: } // createAttribute(int,int,boolean):int
0433:
0434: /** Creates an element definition in the table. */
0435: public int createElementDefinition(int elementNameIndex) {
0436:
0437: // create node
0438: int nodeIndex = createNode(NodeImpl.ELEMENT_DEFINITION_NODE);
0439: int chunk = nodeIndex >> CHUNK_SHIFT;
0440: int index = nodeIndex & CHUNK_MASK;
0441: setChunkIndex(fNodeName, elementNameIndex, chunk, index);
0442:
0443: // return node index
0444: return nodeIndex;
0445:
0446: } // createElementDefinition(int):int
0447:
0448: /** Creates a text node in the table. */
0449: public int createTextNode(int dataIndex, boolean ignorableWhitespace) {
0450:
0451: // create node
0452: int nodeIndex = createNode(Node.TEXT_NODE);
0453: int chunk = nodeIndex >> CHUNK_SHIFT;
0454: int index = nodeIndex & CHUNK_MASK;
0455: setChunkIndex(fNodeValue, dataIndex, chunk, index);
0456: // use last child to store ignorableWhitespace info
0457: setChunkIndex(fNodeLastChild, ignorableWhitespace ? 1 : 0,
0458: chunk, index);
0459:
0460: // return node index
0461: return nodeIndex;
0462:
0463: } // createTextNode(int,boolean):int
0464:
0465: /** Creates a CDATA section node in the table. */
0466: public int createCDATASection(int dataIndex,
0467: boolean ignorableWhitespace) {
0468:
0469: // create node
0470: int nodeIndex = createNode(Node.CDATA_SECTION_NODE);
0471: int chunk = nodeIndex >> CHUNK_SHIFT;
0472: int index = nodeIndex & CHUNK_MASK;
0473: setChunkIndex(fNodeValue, dataIndex, chunk, index);
0474: // use last child to store ignorableWhitespace info
0475: setChunkIndex(fNodeLastChild, ignorableWhitespace ? 1 : 0,
0476: chunk, index);
0477:
0478: // return node index
0479: return nodeIndex;
0480:
0481: } // createCDATASection(int,boolean):int
0482:
0483: /** Creates a processing instruction node in the table. */
0484: public int createProcessingInstruction(int targetIndex,
0485: int dataIndex) {
0486:
0487: // create node
0488: int nodeIndex = createNode(Node.PROCESSING_INSTRUCTION_NODE);
0489: int chunk = nodeIndex >> CHUNK_SHIFT;
0490: int index = nodeIndex & CHUNK_MASK;
0491: setChunkIndex(fNodeName, targetIndex, chunk, index);
0492: setChunkIndex(fNodeValue, dataIndex, chunk, index);
0493:
0494: // return node index
0495: return nodeIndex;
0496:
0497: } // createProcessingInstruction(int,int):int
0498:
0499: /** Creates a comment node in the table. */
0500: public int createComment(int dataIndex) {
0501:
0502: // create node
0503: int nodeIndex = createNode(Node.COMMENT_NODE);
0504: int chunk = nodeIndex >> CHUNK_SHIFT;
0505: int index = nodeIndex & CHUNK_MASK;
0506: setChunkIndex(fNodeValue, dataIndex, chunk, index);
0507:
0508: // return node index
0509: return nodeIndex;
0510:
0511: } // createComment(int):int
0512:
0513: /** Appends a child to the specified parent in the table. */
0514: public void appendChild(int parentIndex, int childIndex) {
0515:
0516: // append parent index
0517: int pchunk = parentIndex >> CHUNK_SHIFT;
0518: int pindex = parentIndex & CHUNK_MASK;
0519: int cchunk = childIndex >> CHUNK_SHIFT;
0520: int cindex = childIndex & CHUNK_MASK;
0521: setChunkIndex(fNodeParent, parentIndex, cchunk, cindex);
0522:
0523: // set previous sibling of new child
0524: int olast = getChunkIndex(fNodeLastChild, pchunk, pindex);
0525: setChunkIndex(fNodePrevSib, olast, cchunk, cindex);
0526:
0527: // update parent's last child
0528: setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex);
0529:
0530: } // appendChild(int,int)
0531:
0532: /** Adds an attribute node to the specified element. */
0533: public int setAttributeNode(int elemIndex, int attrIndex) {
0534:
0535: int echunk = elemIndex >> CHUNK_SHIFT;
0536: int eindex = elemIndex & CHUNK_MASK;
0537: int achunk = attrIndex >> CHUNK_SHIFT;
0538: int aindex = attrIndex & CHUNK_MASK;
0539:
0540: // see if this attribute is already here
0541: String attrName = fStringPool.toString(getChunkIndex(fNodeName,
0542: achunk, aindex));
0543: int oldAttrIndex = getChunkIndex(fNodeValue, echunk, eindex);
0544: int nextIndex = -1;
0545: int oachunk = -1;
0546: int oaindex = -1;
0547: while (oldAttrIndex != -1) {
0548: oachunk = oldAttrIndex >> CHUNK_SHIFT;
0549: oaindex = oldAttrIndex & CHUNK_MASK;
0550: String oldAttrName = fStringPool.toString(getChunkIndex(
0551: fNodeName, oachunk, oaindex));
0552: if (oldAttrName.equals(attrName)) {
0553: break;
0554: }
0555: nextIndex = oldAttrIndex;
0556: oldAttrIndex = getChunkIndex(fNodePrevSib, oachunk, oaindex);
0557: }
0558:
0559: // remove old attribute
0560: if (oldAttrIndex != -1) {
0561:
0562: // patch links
0563: int prevIndex = getChunkIndex(fNodePrevSib, oachunk,
0564: oaindex);
0565: if (nextIndex == -1) {
0566: setChunkIndex(fNodeValue, prevIndex, echunk, eindex);
0567: } else {
0568: int pchunk = nextIndex >> CHUNK_SHIFT;
0569: int pindex = nextIndex & CHUNK_MASK;
0570: setChunkIndex(fNodePrevSib, prevIndex, pchunk, pindex);
0571: }
0572:
0573: // remove connections to siblings
0574: clearChunkIndex(fNodeType, oachunk, oaindex);
0575: clearChunkIndex(fNodeName, oachunk, oaindex);
0576: clearChunkIndex(fNodeValue, oachunk, oaindex);
0577: clearChunkIndex(fNodeParent, oachunk, oaindex);
0578: clearChunkIndex(fNodePrevSib, oachunk, oaindex);
0579: int attrTextIndex = clearChunkIndex(fNodeLastChild,
0580: oachunk, oaindex);
0581: int atchunk = attrTextIndex >> CHUNK_SHIFT;
0582: int atindex = attrTextIndex & CHUNK_MASK;
0583: clearChunkIndex(fNodeType, atchunk, atindex);
0584: clearChunkIndex(fNodeValue, atchunk, atindex);
0585: clearChunkIndex(fNodeParent, atchunk, atindex);
0586: clearChunkIndex(fNodeLastChild, atchunk, atindex);
0587: }
0588:
0589: // add new attribute
0590: int prevIndex = getChunkIndex(fNodeValue, echunk, eindex);
0591: setChunkIndex(fNodeValue, attrIndex, echunk, eindex);
0592: setChunkIndex(fNodePrevSib, prevIndex, achunk, aindex);
0593:
0594: // return
0595: return oldAttrIndex;
0596:
0597: } // setAttributeNode(int,int):int
0598:
0599: /** Inserts a child before the specified node in the table. */
0600: public int insertBefore(int parentIndex, int newChildIndex,
0601: int refChildIndex) {
0602:
0603: if (refChildIndex == -1) {
0604: appendChild(parentIndex, newChildIndex);
0605: return newChildIndex;
0606: }
0607:
0608: int nchunk = newChildIndex >> CHUNK_SHIFT;
0609: int nindex = newChildIndex & CHUNK_MASK;
0610: int rchunk = refChildIndex >> CHUNK_SHIFT;
0611: int rindex = refChildIndex & CHUNK_MASK;
0612: int previousIndex = getChunkIndex(fNodePrevSib, rchunk, rindex);
0613: setChunkIndex(fNodePrevSib, newChildIndex, rchunk, rindex);
0614: setChunkIndex(fNodePrevSib, previousIndex, nchunk, nindex);
0615:
0616: return newChildIndex;
0617:
0618: } // insertBefore(int,int,int):int
0619:
0620: /** Sets the last child of the parentIndex to childIndex. */
0621: public void setAsLastChild(int parentIndex, int childIndex) {
0622:
0623: int pchunk = parentIndex >> CHUNK_SHIFT;
0624: int pindex = parentIndex & CHUNK_MASK;
0625: int chunk = childIndex >> CHUNK_SHIFT;
0626: int index = childIndex & CHUNK_MASK;
0627: setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex);
0628: } // setAsLastChild(int,int)
0629:
0630: /**
0631: * Returns the parent node of the given node.
0632: * <em>Calling this method does not free the parent index.</em>
0633: */
0634: public int getParentNode(int nodeIndex) {
0635: return getParentNode(nodeIndex, false);
0636: }
0637:
0638: /**
0639: * Returns the parent node of the given node.
0640: * @param free True to free parent node.
0641: */
0642: public int getParentNode(int nodeIndex, boolean free) {
0643:
0644: if (nodeIndex == -1) {
0645: return -1;
0646: }
0647:
0648: int chunk = nodeIndex >> CHUNK_SHIFT;
0649: int index = nodeIndex & CHUNK_MASK;
0650: return free ? clearChunkIndex(fNodeParent, chunk, index)
0651: : getChunkIndex(fNodeParent, chunk, index);
0652:
0653: } // getParentNode(int):int
0654:
0655: /** Returns the last child of the given node. */
0656: public int getLastChild(int nodeIndex) {
0657: return getLastChild(nodeIndex, true);
0658: }
0659:
0660: /**
0661: * Returns the last child of the given node.
0662: * @param free True to free child index.
0663: */
0664: public int getLastChild(int nodeIndex, boolean free) {
0665:
0666: if (nodeIndex == -1) {
0667: return -1;
0668: }
0669:
0670: int chunk = nodeIndex >> CHUNK_SHIFT;
0671: int index = nodeIndex & CHUNK_MASK;
0672: return free ? clearChunkIndex(fNodeLastChild, chunk, index)
0673: : getChunkIndex(fNodeLastChild, chunk, index);
0674:
0675: } // getLastChild(int,boolean):int
0676:
0677: /**
0678: * Returns the prev sibling of the given node.
0679: * This is post-normalization of Text Nodes.
0680: */
0681: public int getPrevSibling(int nodeIndex) {
0682: return getPrevSibling(nodeIndex, true);
0683: }
0684:
0685: /**
0686: * Returns the prev sibling of the given node.
0687: * @param free True to free sibling index.
0688: */
0689: public int getPrevSibling(int nodeIndex, boolean free) {
0690:
0691: if (nodeIndex == -1) {
0692: return -1;
0693: }
0694:
0695: int chunk = nodeIndex >> CHUNK_SHIFT;
0696: int index = nodeIndex & CHUNK_MASK;
0697: int type = getChunkIndex(fNodeType, chunk, index);
0698: if (type == Node.TEXT_NODE) {
0699: do {
0700: nodeIndex = getChunkIndex(fNodePrevSib, chunk, index);
0701: if (nodeIndex == -1) {
0702: break;
0703: }
0704: chunk = nodeIndex >> CHUNK_SHIFT;
0705: index = nodeIndex & CHUNK_MASK;
0706: type = getChunkIndex(fNodeType, chunk, index);
0707: } while (type == Node.TEXT_NODE);
0708: } else {
0709: nodeIndex = getChunkIndex(fNodePrevSib, chunk, index);
0710: }
0711:
0712: return nodeIndex;
0713:
0714: } // getPrevSibling(int,boolean):int
0715:
0716: /**
0717: * Returns the <i>real</i> prev sibling of the given node,
0718: * directly from the data structures. Used by TextImpl#getNodeValue()
0719: * to normalize values.
0720: */
0721: public int getRealPrevSibling(int nodeIndex) {
0722: return getRealPrevSibling(nodeIndex, true);
0723: }
0724:
0725: /**
0726: * Returns the <i>real</i> prev sibling of the given node.
0727: * @param free True to free sibling index.
0728: */
0729: public int getRealPrevSibling(int nodeIndex, boolean free) {
0730:
0731: if (nodeIndex == -1) {
0732: return -1;
0733: }
0734:
0735: int chunk = nodeIndex >> CHUNK_SHIFT;
0736: int index = nodeIndex & CHUNK_MASK;
0737: return free ? clearChunkIndex(fNodePrevSib, chunk, index)
0738: : getChunkIndex(fNodePrevSib, chunk, index);
0739:
0740: } // getReadPrevSibling(int,boolean):int
0741:
0742: /**
0743: * Returns the index of the element definition in the table
0744: * with the specified name index, or -1 if no such definition
0745: * exists.
0746: */
0747: public int lookupElementDefinition(int elementNameIndex) {
0748:
0749: if (fNodeCount > 1) {
0750:
0751: // find doctype
0752: int docTypeIndex = -1;
0753: int nchunk = 0;
0754: int nindex = 0;
0755: for (int index = getChunkIndex(fNodeLastChild, nchunk,
0756: nindex); index != -1; index = getChunkIndex(
0757: fNodePrevSib, nchunk, nindex)) {
0758:
0759: nchunk = index >> CHUNK_SHIFT;
0760: nindex = index & CHUNK_MASK;
0761: if (getChunkIndex(fNodeType, nchunk, nindex) == Node.DOCUMENT_TYPE_NODE) {
0762: docTypeIndex = index;
0763: break;
0764: }
0765: }
0766:
0767: // find element definition
0768: if (docTypeIndex == -1) {
0769: return -1;
0770: }
0771: nchunk = docTypeIndex >> CHUNK_SHIFT;
0772: nindex = docTypeIndex & CHUNK_MASK;
0773: for (int index = getChunkIndex(fNodeLastChild, nchunk,
0774: nindex); index != -1; index = getChunkIndex(
0775: fNodePrevSib, nchunk, nindex)) {
0776:
0777: nchunk = index >> CHUNK_SHIFT;
0778: nindex = index & CHUNK_MASK;
0779: if (getChunkIndex(fNodeName, nchunk, nindex) == elementNameIndex) {
0780: return index;
0781: }
0782: }
0783: }
0784:
0785: return -1;
0786:
0787: } // lookupElementDefinition(int):int
0788:
0789: /** Instantiates the requested node object. */
0790: public DeferredNode getNodeObject(int nodeIndex) {
0791:
0792: // is there anything to do?
0793: if (nodeIndex == -1) {
0794: return null;
0795: }
0796:
0797: // get node type
0798: int chunk = nodeIndex >> CHUNK_SHIFT;
0799: int index = nodeIndex & CHUNK_MASK;
0800: int type = getChunkIndex(fNodeType, chunk, index);
0801: if (type != Node.TEXT_NODE) {
0802: clearChunkIndex(fNodeType, chunk, index);
0803: }
0804:
0805: // create new node
0806: DeferredNode node = null;
0807: switch (type) {
0808:
0809: //
0810: // Standard DOM node types
0811: //
0812:
0813: case Node.ATTRIBUTE_NODE: {
0814: if (fNamespacesEnabled) {
0815: node = new DeferredAttrNSImpl(this , nodeIndex);
0816: } else {
0817: node = new DeferredAttrImpl(this , nodeIndex);
0818: }
0819: break;
0820: }
0821:
0822: case Node.CDATA_SECTION_NODE: {
0823: node = new DeferredCDATASectionImpl(this , nodeIndex);
0824: break;
0825: }
0826:
0827: case Node.COMMENT_NODE: {
0828: node = new DeferredCommentImpl(this , nodeIndex);
0829: break;
0830: }
0831:
0832: // NOTE: Document fragments can never be "fast".
0833: //
0834: // The parser will never ask to create a document
0835: // fragment during the parse. Document fragments
0836: // are used by the application *after* the parse.
0837: //
0838: // case Node.DOCUMENT_FRAGMENT_NODE: { break; }
0839: case Node.DOCUMENT_NODE: {
0840: // this node is never "fast"
0841: node = this ;
0842: break;
0843: }
0844:
0845: case Node.DOCUMENT_TYPE_NODE: {
0846: node = new DeferredDocumentTypeImpl(this , nodeIndex);
0847: // save the doctype node
0848: docType = (DocumentTypeImpl) node;
0849: break;
0850: }
0851:
0852: case Node.ELEMENT_NODE: {
0853:
0854: if (DEBUG_IDS) {
0855: System.out.println("getNodeObject(ELEMENT_NODE): "
0856: + nodeIndex);
0857: }
0858:
0859: // create node
0860: if (fNamespacesEnabled) {
0861: node = new DeferredElementNSImpl(this , nodeIndex);
0862: } else {
0863: node = new DeferredElementImpl(this , nodeIndex);
0864: }
0865:
0866: // save the document element node
0867: if (docElement == null) {
0868: docElement = (ElementImpl) node;
0869: }
0870:
0871: // check to see if this element needs to be
0872: // registered for its ID attributes
0873: if (fIdElement != null) {
0874: int idIndex = DeferredDocumentImpl.binarySearch(
0875: fIdElement, 0, fIdCount - 1, nodeIndex);
0876: while (idIndex != -1) {
0877:
0878: if (DEBUG_IDS) {
0879: System.out.println(" id index: " + idIndex);
0880: System.out.println(" fIdName[" + idIndex
0881: + "]: " + fIdName[idIndex]);
0882: }
0883:
0884: // register ID
0885: int nameIndex = fIdName[idIndex];
0886: if (nameIndex != -1) {
0887: String name = fStringPool.toString(nameIndex);
0888: if (DEBUG_IDS) {
0889: System.out.println(" name: " + name);
0890: System.out.print("getNodeObject()#");
0891: }
0892: putIdentifier0(name, (Element) node);
0893: fIdName[idIndex] = -1;
0894: }
0895:
0896: // continue if there are more IDs for
0897: // this element
0898: if (idIndex + 1 < fIdCount
0899: && fIdElement[idIndex + 1] == nodeIndex) {
0900: idIndex++;
0901: } else {
0902: idIndex = -1;
0903: }
0904: }
0905: }
0906: break;
0907: }
0908:
0909: case Node.ENTITY_NODE: {
0910: node = new DeferredEntityImpl(this , nodeIndex);
0911: break;
0912: }
0913:
0914: case Node.ENTITY_REFERENCE_NODE: {
0915: node = new DeferredEntityReferenceImpl(this , nodeIndex);
0916: break;
0917: }
0918:
0919: case Node.NOTATION_NODE: {
0920: node = new DeferredNotationImpl(this , nodeIndex);
0921: break;
0922: }
0923:
0924: case Node.PROCESSING_INSTRUCTION_NODE: {
0925: node = new DeferredProcessingInstructionImpl(this ,
0926: nodeIndex);
0927: break;
0928: }
0929:
0930: case Node.TEXT_NODE: {
0931: node = new DeferredTextImpl(this , nodeIndex);
0932: break;
0933: }
0934:
0935: //
0936: // non-standard DOM node types
0937: //
0938:
0939: case NodeImpl.ELEMENT_DEFINITION_NODE: {
0940: node = new DeferredElementDefinitionImpl(this , nodeIndex);
0941: break;
0942: }
0943:
0944: default: {
0945: throw new IllegalArgumentException("type: " + type);
0946: }
0947:
0948: } // switch node type
0949:
0950: // store and return
0951: if (node != null) {
0952: return node;
0953: }
0954:
0955: // error
0956: throw new IllegalArgumentException();
0957:
0958: } // createNodeObject(int):Node
0959:
0960: /** Returns the name of the given node. */
0961: public String getNodeNameString(int nodeIndex) {
0962: return getNodeNameString(nodeIndex, true);
0963: } // getNodeNameString(int):String
0964:
0965: /**
0966: * Returns the name of the given node.
0967: * @param free True to free the string index.
0968: */
0969: public String getNodeNameString(int nodeIndex, boolean free) {
0970:
0971: if (nodeIndex == -1) {
0972: return null;
0973: }
0974:
0975: int chunk = nodeIndex >> CHUNK_SHIFT;
0976: int index = nodeIndex & CHUNK_MASK;
0977: int nameIndex = free ? clearChunkIndex(fNodeName, chunk, index)
0978: : getChunkIndex(fNodeName, chunk, index);
0979: if (nameIndex == -1) {
0980: return null;
0981: }
0982:
0983: return fStringPool.toString(nameIndex);
0984:
0985: } // getNodeNameString(int,boolean):String
0986:
0987: /** Returns the value of the given node. */
0988: public String getNodeValueString(int nodeIndex) {
0989: return getNodeValueString(nodeIndex, true);
0990: } // getNodeValueString(int):String
0991:
0992: /**
0993: * Returns the value of the given node.
0994: * @param free True to free the string index.
0995: */
0996: public String getNodeValueString(int nodeIndex, boolean free) {
0997:
0998: if (nodeIndex == -1) {
0999: return null;
1000: }
1001:
1002: int chunk = nodeIndex >> CHUNK_SHIFT;
1003: int index = nodeIndex & CHUNK_MASK;
1004: int valueIndex = free ? clearChunkIndex(fNodeValue, chunk,
1005: index) : getChunkIndex(fNodeValue, chunk, index);
1006: if (valueIndex == -1) {
1007: return null;
1008: }
1009:
1010: int type = getChunkIndex(fNodeType, chunk, index);
1011: if (type == Node.TEXT_NODE) {
1012: int prevSib = getRealPrevSibling(nodeIndex);
1013: if (prevSib != -1
1014: && getNodeType(prevSib, false) == Node.TEXT_NODE) {
1015: fStrChunks.addElement(fStringPool.toString(valueIndex));
1016: do {
1017: chunk = prevSib >> CHUNK_SHIFT;
1018: index = prevSib & CHUNK_MASK;
1019: valueIndex = getChunkIndex(fNodeValue, chunk, index);
1020: // NOTE: This has to be done backwards because the
1021: // children are placed backwards.
1022: fStrChunks.addElement(fStringPool
1023: .toString(valueIndex));
1024: prevSib = getChunkIndex(fNodePrevSib, chunk, index);
1025: if (prevSib == -1) {
1026: break;
1027: }
1028: } while (getNodeType(prevSib, false) == Node.TEXT_NODE);
1029: for (int i = fStrChunks.size() - 1; i >= 0; i--) {
1030: fBufferStr.append((String) fStrChunks.elementAt(i));
1031: }
1032:
1033: String value = fBufferStr.toString();
1034: fStrChunks.setSize(0);
1035: fBufferStr.setLength(0);
1036: return value;
1037: }
1038: }
1039:
1040: return fStringPool.toString(valueIndex);
1041:
1042: } // getNodeValueString(int,boolean):String
1043:
1044: /** Returns the real int name of the given node. */
1045: public int getNodeName(int nodeIndex) {
1046: return getNodeName(nodeIndex, true);
1047: }
1048:
1049: /**
1050: * Returns the real int name of the given node.
1051: * @param free True to free the name index.
1052: */
1053: public int getNodeName(int nodeIndex, boolean free) {
1054:
1055: if (nodeIndex == -1) {
1056: return -1;
1057: }
1058:
1059: int chunk = nodeIndex >> CHUNK_SHIFT;
1060: int index = nodeIndex & CHUNK_MASK;
1061: return free ? clearChunkIndex(fNodeName, chunk, index)
1062: : getChunkIndex(fNodeName, chunk, index);
1063:
1064: } // getNodeName(int,boolean):int
1065:
1066: /**
1067: * Returns the real int value of the given node.
1068: * Used by AttrImpl to store specified value (1 == true).
1069: */
1070: public int getNodeValue(int nodeIndex) {
1071: return getNodeValue(nodeIndex, true);
1072: }
1073:
1074: /**
1075: * Returns the real int value of the given node.
1076: * @param free True to free the value index.
1077: */
1078: public int getNodeValue(int nodeIndex, boolean free) {
1079:
1080: if (nodeIndex == -1) {
1081: return -1;
1082: }
1083:
1084: int chunk = nodeIndex >> CHUNK_SHIFT;
1085: int index = nodeIndex & CHUNK_MASK;
1086: return free ? clearChunkIndex(fNodeValue, chunk, index)
1087: : getChunkIndex(fNodeValue, chunk, index);
1088:
1089: } // getNodeValue(int,boolean):int
1090:
1091: /** Returns the type of the given node. */
1092: public short getNodeType(int nodeIndex) {
1093: return getNodeType(nodeIndex, true);
1094: }
1095:
1096: /**
1097: * Returns the type of the given node.
1098: * @param True to free type index.
1099: */
1100: public short getNodeType(int nodeIndex, boolean free) {
1101:
1102: if (nodeIndex == -1) {
1103: return -1;
1104: }
1105:
1106: int chunk = nodeIndex >> CHUNK_SHIFT;
1107: int index = nodeIndex & CHUNK_MASK;
1108: if (free) {
1109: return (short) clearChunkIndex(fNodeType, chunk, index);
1110: }
1111: return (short) getChunkIndex(fNodeType, chunk, index);
1112:
1113: } // getNodeType(int):int
1114:
1115: /** Returns the attribute value of the given name. */
1116: public int getAttribute(int elemIndex, int nameIndex) {
1117: if (elemIndex == -1 || nameIndex == -1) {
1118: return -1;
1119: }
1120: int echunk = elemIndex >> CHUNK_SHIFT;
1121: int eindex = elemIndex & CHUNK_MASK;
1122: int attrIndex = getChunkIndex(fNodeValue, echunk, eindex);
1123: while (attrIndex != -1) {
1124: int achunk = attrIndex >> CHUNK_SHIFT;
1125: int aindex = attrIndex & CHUNK_MASK;
1126: if (getChunkIndex(fNodeName, achunk, aindex) == nameIndex) {
1127: return getChunkIndex(fNodeValue, achunk, aindex);
1128: }
1129: attrIndex = getChunkIndex(fNodePrevSib, achunk, aindex);
1130: }
1131: return -1;
1132: }
1133:
1134: /** Returns the URI of the given node. */
1135: public short getNodeURI(int nodeIndex) {
1136: return getNodeURI(nodeIndex, true);
1137: }
1138:
1139: /**
1140: * Returns the URI of the given node.
1141: * @param True to free URI index.
1142: */
1143: public short getNodeURI(int nodeIndex, boolean free) {
1144:
1145: if (nodeIndex == -1) {
1146: return -1;
1147: }
1148:
1149: int chunk = nodeIndex >> CHUNK_SHIFT;
1150: int index = nodeIndex & CHUNK_MASK;
1151: if (free) {
1152: return (short) clearChunkIndex(fNodeURI, chunk, index);
1153: }
1154: return (short) getChunkIndex(fNodeURI, chunk, index);
1155:
1156: } // getNodeURI(int):int
1157:
1158: // identifier maintenance
1159:
1160: /** Registers an identifier name with a specified element node. */
1161: public void putIdentifier(int nameIndex, int elementNodeIndex) {
1162:
1163: if (DEBUG_IDS) {
1164: System.out.println("putIdentifier("
1165: + nameIndex
1166: + ", "
1167: + elementNodeIndex
1168: + ')'
1169: + " // "
1170: + fStringPool.toString(nameIndex)
1171: + ", "
1172: + fStringPool.toString(getChunkIndex(fNodeName,
1173: elementNodeIndex >> CHUNK_SHIFT,
1174: elementNodeIndex & CHUNK_MASK)));
1175: }
1176:
1177: // initialize arrays
1178: if (fIdName == null) {
1179: fIdName = new int[64];
1180: fIdElement = new int[64];
1181: }
1182:
1183: // resize arrays
1184: if (fIdCount == fIdName.length) {
1185: int idName[] = new int[fIdCount * 2];
1186: System.arraycopy(fIdName, 0, idName, 0, fIdCount);
1187: fIdName = idName;
1188:
1189: int idElement[] = new int[idName.length];
1190: System.arraycopy(fIdElement, 0, idElement, 0, fIdCount);
1191: fIdElement = idElement;
1192: }
1193:
1194: // store identifier
1195: fIdName[fIdCount] = nameIndex;
1196: fIdElement[fIdCount] = elementNodeIndex;
1197: fIdCount++;
1198:
1199: } // putIdentifier(int,int)
1200:
1201: //
1202: // DEBUG
1203: //
1204:
1205: /** Prints out the tables. */
1206: public void print() {
1207:
1208: if (DEBUG_PRINT_REF_COUNTS) {
1209: System.out.print("num\t");
1210: System.out.print("type\t");
1211: System.out.print("name\t");
1212: System.out.print("val\t");
1213: System.out.print("par\t");
1214: System.out.print("fch\t");
1215: System.out.print("nsib");
1216: System.out.println();
1217: for (int i = 0; i < fNodeType.length; i++) {
1218: if (fNodeType[i] != null) {
1219: // separator
1220: System.out.print("--------");
1221: System.out.print("--------");
1222: System.out.print("--------");
1223: System.out.print("--------");
1224: System.out.print("--------");
1225: System.out.print("--------");
1226: System.out.print("--------");
1227: System.out.println();
1228:
1229: // set count
1230: System.out.print(i);
1231: System.out.print('\t');
1232: System.out.print(fNodeType[i][CHUNK_SIZE]);
1233: System.out.print('\t');
1234: System.out.print(fNodeName[i][CHUNK_SIZE]);
1235: System.out.print('\t');
1236: System.out.print(fNodeValue[i][CHUNK_SIZE]);
1237: System.out.print('\t');
1238: System.out.print(fNodeParent[i][CHUNK_SIZE]);
1239: System.out.print('\t');
1240: System.out.print(fNodeLastChild[i][CHUNK_SIZE]);
1241: System.out.print('\t');
1242: System.out.print(fNodePrevSib[i][CHUNK_SIZE]);
1243: System.out.println();
1244:
1245: // clear count
1246: System.out.print(i);
1247: System.out.print('\t');
1248: System.out.print(fNodeType[i][CHUNK_SIZE + 1]);
1249: System.out.print('\t');
1250: System.out.print(fNodeName[i][CHUNK_SIZE + 1]);
1251: System.out.print('\t');
1252: System.out.print(fNodeValue[i][CHUNK_SIZE + 1]);
1253: System.out.print('\t');
1254: System.out.print(fNodeParent[i][CHUNK_SIZE + 1]);
1255: System.out.print('\t');
1256: System.out.print(fNodeLastChild[i][CHUNK_SIZE + 1]);
1257: System.out.print('\t');
1258: System.out.print(fNodePrevSib[i][CHUNK_SIZE + 1]);
1259: System.out.println();
1260: }
1261: }
1262: }
1263:
1264: if (DEBUG_PRINT_TABLES) {
1265: // This assumes that the document is small
1266: System.out.println("# start table");
1267: for (int i = 0; i < fNodeCount; i++) {
1268: int chunk = i >> CHUNK_SHIFT;
1269: int index = i & CHUNK_MASK;
1270: if (i % 10 == 0) {
1271: System.out.print("num\t");
1272: System.out.print("type\t");
1273: System.out.print("name\t");
1274: System.out.print("val\t");
1275: System.out.print("par\t");
1276: System.out.print("fch\t");
1277: System.out.print("nsib");
1278: System.out.println();
1279: }
1280: System.out.print(i);
1281: System.out.print('\t');
1282: System.out
1283: .print(getChunkIndex(fNodeType, chunk, index));
1284: System.out.print('\t');
1285: System.out
1286: .print(getChunkIndex(fNodeName, chunk, index));
1287: System.out.print('\t');
1288: System.out
1289: .print(getChunkIndex(fNodeValue, chunk, index));
1290: System.out.print('\t');
1291: System.out.print(getChunkIndex(fNodeParent, chunk,
1292: index));
1293: System.out.print('\t');
1294: System.out.print(getChunkIndex(fNodeLastChild, chunk,
1295: index));
1296: System.out.print('\t');
1297: System.out.print(getChunkIndex(fNodePrevSib, chunk,
1298: index));
1299: /***
1300: System.out.print(fNodeType[0][i]);
1301: System.out.print('\t');
1302: System.out.print(fNodeName[0][i]);
1303: System.out.print('\t');
1304: System.out.print(fNodeValue[0][i]);
1305: System.out.print('\t');
1306: System.out.print(fNodeParent[0][i]);
1307: System.out.print('\t');
1308: System.out.print(fNodeFirstChild[0][i]);
1309: System.out.print('\t');
1310: System.out.print(fNodeLastChild[0][i]);
1311: System.out.print('\t');
1312: System.out.print(fNodePrevSib[0][i]);
1313: System.out.print('\t');
1314: System.out.print(fNodeNextSib[0][i]);
1315: /***/
1316: System.out.println();
1317: }
1318: System.out.println("# end table");
1319: }
1320:
1321: } // print()
1322:
1323: //
1324: // DeferredNode methods
1325: //
1326:
1327: /** Returns the node index. */
1328: public int getNodeIndex() {
1329: return 0;
1330: }
1331:
1332: //
1333: // Protected methods
1334: //
1335:
1336: /** access to string pool. */
1337: protected StringPool getStringPool() {
1338: return fStringPool;
1339: }
1340:
1341: /** Synchronizes the node's data. */
1342: protected void synchronizeData() {
1343:
1344: // no need to sync in the future
1345: needsSyncData(false);
1346:
1347: // fluff up enough nodes to fill identifiers hash
1348: if (fIdElement != null) {
1349:
1350: // REVISIT: There has to be a more efficient way of
1351: // doing this. But keep in mind that the
1352: // tree can have been altered and re-ordered
1353: // before all of the element nodes with ID
1354: // attributes have been registered. For now
1355: // this is reasonable and safe. -Ac
1356:
1357: IntVector path = new IntVector();
1358: for (int i = 0; i < fIdCount; i++) {
1359:
1360: // ignore if it's already been registered
1361: int elementNodeIndex = fIdElement[i];
1362: int idNameIndex = fIdName[i];
1363: if (idNameIndex == -1) {
1364: continue;
1365: }
1366:
1367: // find path from this element to the root
1368: path.removeAllElements();
1369: int index = elementNodeIndex;
1370: do {
1371: path.addElement(index);
1372: int pchunk = index >> CHUNK_SHIFT;
1373: int pindex = index & CHUNK_MASK;
1374: index = getChunkIndex(fNodeParent, pchunk, pindex);
1375: } while (index != -1);
1376:
1377: // Traverse path (backwards), fluffing the elements
1378: // along the way. When this loop finishes, "place"
1379: // will contain the reference to the element node
1380: // we're interested in. -Ac
1381: Node place = this ;
1382: for (int j = path.size() - 2; j >= 0; j--) {
1383: index = path.elementAt(j);
1384: Node child = place.getLastChild();
1385: while (child != null) {
1386: if (child instanceof DeferredNode) {
1387: int nodeIndex = ((DeferredNode) child)
1388: .getNodeIndex();
1389: if (nodeIndex == index) {
1390: place = child;
1391: break;
1392: }
1393: }
1394: child = child.getPreviousSibling();
1395: }
1396: }
1397:
1398: // register the element
1399: Element element = (Element) place;
1400: String name = fStringPool.toString(idNameIndex);
1401: putIdentifier0(name, element);
1402: fIdName[i] = -1;
1403:
1404: // see if there are more IDs on this element
1405: while (i + 1 < fIdCount
1406: && fIdElement[i + 1] == elementNodeIndex) {
1407: idNameIndex = fIdName[++i];
1408: if (idNameIndex == -1) {
1409: continue;
1410: }
1411: name = fStringPool.toString(idNameIndex);
1412: putIdentifier0(name, element);
1413: }
1414: }
1415:
1416: } // if identifiers
1417:
1418: } // synchronizeData()
1419:
1420: /**
1421: * Synchronizes the node's children with the internal structure.
1422: * Fluffing the children at once solves a lot of work to keep
1423: * the two structures in sync. The problem gets worse when
1424: * editing the tree -- this makes it a lot easier.
1425: */
1426: protected void synchronizeChildren() {
1427:
1428: if (needsSyncData()) {
1429: synchronizeData();
1430: /*
1431: * when we have elements with IDs this method is being recursively
1432: * called from synchronizeData, in which case we've already gone
1433: * through the following and we can now simply stop here.
1434: */
1435: if (!needsSyncChildren()) {
1436: return;
1437: }
1438: }
1439:
1440: // we don't want to generate any event for this so turn them off
1441: boolean orig = mutationEvents;
1442: mutationEvents = false;
1443:
1444: // no need to sync in the future
1445: needsSyncChildren(false);
1446:
1447: getNodeType(0);
1448:
1449: // create children and link them as siblings
1450: ChildNode first = null;
1451: ChildNode last = null;
1452: for (int index = getLastChild(0); index != -1; index = getPrevSibling(index)) {
1453:
1454: ChildNode node = (ChildNode) getNodeObject(index);
1455: if (last == null) {
1456: last = node;
1457: } else {
1458: first.previousSibling = node;
1459: }
1460: node.ownerNode = this ;
1461: node.isOwned(true);
1462: node.nextSibling = first;
1463: first = node;
1464:
1465: // save doctype and document type
1466: int type = node.getNodeType();
1467: if (type == Node.ELEMENT_NODE) {
1468: docElement = (ElementImpl) node;
1469: } else if (type == Node.DOCUMENT_TYPE_NODE) {
1470: docType = (DocumentTypeImpl) node;
1471: }
1472: }
1473:
1474: if (first != null) {
1475: firstChild = first;
1476: first.isFirstChild(true);
1477: lastChild(last);
1478: }
1479:
1480: // set mutation events flag back to its original value
1481: mutationEvents = orig;
1482:
1483: } // synchronizeChildren()
1484:
1485: /**
1486: * Synchronizes the node's children with the internal structure.
1487: * Fluffing the children at once solves a lot of work to keep
1488: * the two structures in sync. The problem gets worse when
1489: * editing the tree -- this makes it a lot easier.
1490: * This is not directly used in this class but this method is
1491: * here so that it can be shared by all deferred subclasses of AttrImpl.
1492: */
1493: protected final void synchronizeChildren(AttrImpl a, int nodeIndex) {
1494:
1495: // we don't want to generate any event for this so turn them off
1496: boolean orig = getMutationEvents();
1497: setMutationEvents(false);
1498:
1499: // no need to sync in the future
1500: a.needsSyncChildren(false);
1501:
1502: // create children and link them as siblings or simply store the value
1503: // as a String if all we have is one piece of text
1504: int last = getLastChild(nodeIndex);
1505: int prev = getPrevSibling(last);
1506: if (prev == -1) {
1507: a.value = getNodeValueString(last);
1508: a.hasStringValue(true);
1509: } else {
1510: ChildNode firstNode = null;
1511: ChildNode lastNode = null;
1512: for (int index = last; index != -1; index = getPrevSibling(index)) {
1513:
1514: ChildNode node = (ChildNode) getNodeObject(index);
1515: if (lastNode == null) {
1516: lastNode = node;
1517: } else {
1518: firstNode.previousSibling = node;
1519: }
1520: node.ownerNode = a;
1521: node.isOwned(true);
1522: node.nextSibling = firstNode;
1523: firstNode = node;
1524: }
1525: if (lastNode != null) {
1526: a.value = firstNode; // firstChild = firstNode
1527: firstNode.isFirstChild(true);
1528: a.lastChild(lastNode);
1529: }
1530: a.hasStringValue(false);
1531: }
1532:
1533: // set mutation events flag back to its original value
1534: setMutationEvents(orig);
1535:
1536: } // synchronizeChildren(AttrImpl,int):void
1537:
1538: /**
1539: * Synchronizes the node's children with the internal structure.
1540: * Fluffing the children at once solves a lot of work to keep
1541: * the two structures in sync. The problem gets worse when
1542: * editing the tree -- this makes it a lot easier.
1543: * This is not directly used in this class but this method is
1544: * here so that it can be shared by all deferred subclasses of ParentNode.
1545: */
1546: protected final void synchronizeChildren(ParentNode p, int nodeIndex) {
1547:
1548: // we don't want to generate any event for this so turn them off
1549: boolean orig = getMutationEvents();
1550: setMutationEvents(false);
1551:
1552: // no need to sync in the future
1553: p.needsSyncChildren(false);
1554:
1555: // create children and link them as siblings
1556: ChildNode firstNode = null;
1557: ChildNode lastNode = null;
1558: for (int index = getLastChild(nodeIndex); index != -1; index = getPrevSibling(index)) {
1559:
1560: ChildNode node = (ChildNode) getNodeObject(index);
1561: if (lastNode == null) {
1562: lastNode = node;
1563: } else {
1564: firstNode.previousSibling = node;
1565: }
1566: node.ownerNode = p;
1567: node.isOwned(true);
1568: node.nextSibling = firstNode;
1569: firstNode = node;
1570: }
1571: if (lastNode != null) {
1572: p.firstChild = firstNode;
1573: firstNode.isFirstChild(true);
1574: p.lastChild(lastNode);
1575: }
1576:
1577: // set mutation events flag back to its original value
1578: setMutationEvents(orig);
1579:
1580: } // synchronizeChildren(ParentNode,int):void
1581:
1582: // utility methods
1583:
1584: /** Ensures that the internal tables are large enough. */
1585: protected boolean ensureCapacity(int chunk, int index) {
1586:
1587: // create buffers
1588: if (fNodeType == null) {
1589: fNodeType = new int[INITIAL_CHUNK_COUNT][];
1590: fNodeName = new int[INITIAL_CHUNK_COUNT][];
1591: fNodeValue = new int[INITIAL_CHUNK_COUNT][];
1592: fNodeParent = new int[INITIAL_CHUNK_COUNT][];
1593: fNodeLastChild = new int[INITIAL_CHUNK_COUNT][];
1594: fNodePrevSib = new int[INITIAL_CHUNK_COUNT][];
1595: fNodeURI = new int[INITIAL_CHUNK_COUNT][];
1596: }
1597:
1598: // return true if table is already big enough
1599: try {
1600: return fNodeType[chunk][index] != 0;
1601: }
1602:
1603: // resize the tables
1604: catch (ArrayIndexOutOfBoundsException ex) {
1605: int newsize = chunk * 2;
1606:
1607: int[][] newArray = new int[newsize][];
1608: System.arraycopy(fNodeType, 0, newArray, 0, chunk);
1609: fNodeType = newArray;
1610:
1611: newArray = new int[newsize][];
1612: System.arraycopy(fNodeName, 0, newArray, 0, chunk);
1613: fNodeName = newArray;
1614:
1615: newArray = new int[newsize][];
1616: System.arraycopy(fNodeValue, 0, newArray, 0, chunk);
1617: fNodeValue = newArray;
1618:
1619: newArray = new int[newsize][];
1620: System.arraycopy(fNodeParent, 0, newArray, 0, chunk);
1621: fNodeParent = newArray;
1622:
1623: newArray = new int[newsize][];
1624: System.arraycopy(fNodeLastChild, 0, newArray, 0, chunk);
1625: fNodeLastChild = newArray;
1626:
1627: newArray = new int[newsize][];
1628: System.arraycopy(fNodePrevSib, 0, newArray, 0, chunk);
1629: fNodePrevSib = newArray;
1630:
1631: newArray = new int[newsize][];
1632: System.arraycopy(fNodeURI, 0, newArray, 0, chunk);
1633: fNodeURI = newArray;
1634: }
1635:
1636: catch (NullPointerException ex) {
1637: // ignore
1638: }
1639:
1640: // create chunks
1641: createChunk(fNodeType, chunk);
1642: createChunk(fNodeName, chunk);
1643: createChunk(fNodeValue, chunk);
1644: createChunk(fNodeParent, chunk);
1645: createChunk(fNodeLastChild, chunk);
1646: createChunk(fNodePrevSib, chunk);
1647: createChunk(fNodeURI, chunk);
1648:
1649: // success
1650: return true;
1651:
1652: } // ensureCapacity(int,int):boolean
1653:
1654: /** Creates a node of the specified type. */
1655: protected int createNode(short nodeType) {
1656:
1657: // ensure tables are large enough
1658: int chunk = fNodeCount >> CHUNK_SHIFT;
1659: int index = fNodeCount & CHUNK_MASK;
1660: ensureCapacity(chunk, index);
1661:
1662: // initialize node
1663: setChunkIndex(fNodeType, nodeType, chunk, index);
1664:
1665: // return node index number
1666: return fNodeCount++;
1667:
1668: } // createNode(short):int
1669:
1670: /**
1671: * Performs a binary search for a target value in an array of
1672: * values. The array of values must be in ascending sorted order
1673: * before calling this method and all array values must be
1674: * non-negative.
1675: *
1676: * @param values The array of values to search.
1677: * @param start The starting offset of the search.
1678: * @param end The ending offset of the search.
1679: * @param target The target value.
1680: *
1681: * @return This function will return the <i>first</i> occurrence
1682: * of the target value, or -1 if the target value cannot
1683: * be found.
1684: */
1685: protected static int binarySearch(final int values[], int start,
1686: int end, int target) {
1687:
1688: if (DEBUG_IDS) {
1689: System.out.println("binarySearch(), target: " + target);
1690: }
1691:
1692: // look for target value
1693: while (start <= end) {
1694:
1695: // is this the one we're looking for?
1696: int middle = (start + end) / 2;
1697: int value = values[middle];
1698: if (DEBUG_IDS) {
1699: System.out.print(" value: " + value + ", target: "
1700: + target + " // ");
1701: print(values, start, end, middle, target);
1702: }
1703: if (value == target) {
1704: while (middle > 0 && values[middle - 1] == target) {
1705: middle--;
1706: }
1707: if (DEBUG_IDS) {
1708: System.out.println("FOUND AT " + middle);
1709: }
1710: return middle;
1711: }
1712:
1713: // is this point higher or lower?
1714: if (value > target) {
1715: end = middle - 1;
1716: } else {
1717: start = middle + 1;
1718: }
1719:
1720: } // while
1721:
1722: // not found
1723: if (DEBUG_IDS) {
1724: System.out.println("NOT FOUND!");
1725: }
1726: return -1;
1727:
1728: } // binarySearch(int[],int,int,int):int
1729:
1730: //
1731: // Private methods
1732: //
1733:
1734: /** Creates the specified chunk in the given array of chunks. */
1735: private final void createChunk(int data[][], int chunk) {
1736: data[chunk] = new int[CHUNK_SIZE + 2];
1737: for (int i = 0; i < CHUNK_SIZE; i++) {
1738: data[chunk][i] = -1;
1739: }
1740: }
1741:
1742: /**
1743: * Sets the specified value in the given of data at the chunk and index.
1744: *
1745: * @return Returns the old value.
1746: */
1747: private final int setChunkIndex(int data[][], int value, int chunk,
1748: int index) {
1749: if (value == -1) {
1750: return clearChunkIndex(data, chunk, index);
1751: }
1752: int ovalue = data[chunk][index];
1753: if (ovalue == -1) {
1754: data[chunk][CHUNK_SIZE]++;
1755: }
1756: data[chunk][index] = value;
1757: return ovalue;
1758: }
1759:
1760: /**
1761: * Returns the specified value in the given data at the chunk and index.
1762: */
1763: private final int getChunkIndex(int data[][], int chunk, int index) {
1764: return data[chunk] != null ? data[chunk][index] : -1;
1765: }
1766:
1767: /**
1768: * Clears the specified value in the given data at the chunk and index.
1769: * Note that this method will clear the given chunk if the reference
1770: * count becomes zero.
1771: *
1772: * @return Returns the old value.
1773: */
1774: private final int clearChunkIndex(int data[][], int chunk, int index) {
1775: int value = data[chunk] != null ? data[chunk][index] : -1;
1776: if (value != -1) {
1777: data[chunk][CHUNK_SIZE + 1]++;
1778: data[chunk][index] = -1;
1779: if (data[chunk][CHUNK_SIZE] == data[chunk][CHUNK_SIZE + 1]) {
1780: data[chunk] = null;
1781: }
1782: }
1783: return value;
1784: }
1785:
1786: /**
1787: * This version of putIdentifier is needed to avoid fluffing
1788: * all of the paths to ID attributes when a node object is
1789: * created that contains an ID attribute.
1790: */
1791: private final void putIdentifier0(String idName, Element element) {
1792:
1793: if (DEBUG_IDS) {
1794: System.out.println("putIdentifier0(" + idName + ", "
1795: + element + ')');
1796: }
1797:
1798: // create hashtable
1799: if (identifiers == null) {
1800: identifiers = new java.util.Hashtable();
1801: }
1802:
1803: // save ID and its associated element
1804: identifiers.put(idName, element);
1805:
1806: } // putIdentifier0(String,Element)
1807:
1808: /** Prints the ID array. */
1809: private static void print(int values[], int start, int end,
1810: int middle, int target) {
1811:
1812: if (DEBUG_IDS) {
1813: System.out.print(start);
1814: System.out.print(" [");
1815: for (int i = start; i < end; i++) {
1816: if (middle == i) {
1817: System.out.print("!");
1818: }
1819: System.out.print(values[i]);
1820: if (values[i] == target) {
1821: System.out.print("*");
1822: }
1823: if (i < end - 1) {
1824: System.out.print(" ");
1825: }
1826: }
1827: System.out.println("] " + end);
1828: }
1829:
1830: } // print(int[],int,int,int,int)
1831:
1832: //
1833: // Classes
1834: //
1835:
1836: /**
1837: * A simple integer vector.
1838: */
1839: static class IntVector {
1840:
1841: //
1842: // Data
1843: //
1844:
1845: /** Data. */
1846: private int data[];
1847:
1848: /** Size. */
1849: private int size;
1850:
1851: //
1852: // Public methods
1853: //
1854:
1855: /** Returns the length of this vector. */
1856: public int size() {
1857: return size;
1858: }
1859:
1860: /** Returns the element at the specified index. */
1861: public int elementAt(int index) {
1862: return data[index];
1863: }
1864:
1865: /** Appends an element to the end of the vector. */
1866: public void addElement(int element) {
1867: ensureCapacity(size + 1);
1868: data[size++] = element;
1869: }
1870:
1871: /** Clears the vector. */
1872: public void removeAllElements() {
1873: size = 0;
1874: }
1875:
1876: //
1877: // Private methods
1878: //
1879:
1880: /** Makes sure that there is enough storage. */
1881: private void ensureCapacity(int newsize) {
1882:
1883: if (data == null) {
1884: data = new int[newsize + 15];
1885: } else if (newsize > data.length) {
1886: int newdata[] = new int[newsize + 15];
1887: System.arraycopy(data, 0, newdata, 0, data.length);
1888: data = newdata;
1889: }
1890:
1891: } // ensureCapacity(int)
1892:
1893: } // class IntVector
1894:
1895: } // class DeferredDocumentImpl
|