0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.xerces.dom;
0019:
0020: import org.w3c.dom.DOMImplementation;
0021: import org.w3c.dom.Element;
0022: import org.w3c.dom.Node;
0023:
0024: import java.util.Vector;
0025:
0026: /**
0027: * The Document interface represents the entire HTML or XML document.
0028: * Conceptually, it is the root of the document tree, and provides the
0029: * primary access to the document's data.
0030: * <P>
0031: * Since elements, text nodes, comments, processing instructions,
0032: * etc. cannot exist outside the context of a Document, the Document
0033: * interface also contains the factory methods needed to create these
0034: * objects. The Node objects created have a ownerDocument attribute
0035: * which associates them with the Document within whose context they
0036: * were created.
0037: *
0038: * @xerces.internal
0039: *
0040: * @version $Id: DeferredDocumentImpl.java 511134 2007-02-23 22:08:04Z mrglavas $
0041: * @since PR-DOM-Level-1-19980818.
0042: */
0043: public class DeferredDocumentImpl extends DocumentImpl implements
0044: DeferredNode {
0045:
0046: //
0047: // Constants
0048: //
0049:
0050: /** Serialization version. */
0051: static final long serialVersionUID = 5186323580749626857L;
0052:
0053: // debugging
0054:
0055: /** To include code for printing the ref count tables. */
0056: private static final boolean DEBUG_PRINT_REF_COUNTS = false;
0057:
0058: /** To include code for printing the internal tables. */
0059: private static final boolean DEBUG_PRINT_TABLES = false;
0060:
0061: /** To debug identifiers set to true and recompile. */
0062: private static final boolean DEBUG_IDS = false;
0063:
0064: // protected
0065:
0066: /** Chunk shift. */
0067: protected static final int CHUNK_SHIFT = 11; // 2^11 = 2k
0068:
0069: /** Chunk size. */
0070: protected static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
0071:
0072: /** Chunk mask. */
0073: protected static final int CHUNK_MASK = CHUNK_SIZE - 1;
0074:
0075: /** Initial chunk size. */
0076: protected static final int INITIAL_CHUNK_COUNT = (1 << (16 - CHUNK_SHIFT)); // 2^16 = 64k
0077:
0078: //
0079: // Data
0080: //
0081:
0082: // lazy-eval information
0083: // To maximize memory consumption the actual semantic of these fields vary
0084: // depending on the node type.
0085:
0086: /** Node count. */
0087: protected transient int fNodeCount = 0;
0088:
0089: /** Node types. */
0090: protected transient int fNodeType[][];
0091:
0092: /** Node names. */
0093: protected transient Object fNodeName[][];
0094:
0095: /** Node values. */
0096: protected transient Object fNodeValue[][];
0097:
0098: /** Node parents. */
0099: protected transient int fNodeParent[][];
0100:
0101: /** Node first children. */
0102: protected transient int fNodeLastChild[][];
0103:
0104: /** Node prev siblings. */
0105: protected transient int fNodePrevSib[][];
0106:
0107: /** Node namespace URI. */
0108: protected transient Object fNodeURI[][];
0109:
0110: /** Extra data. */
0111: protected transient int fNodeExtra[][];
0112:
0113: /** Identifier count. */
0114: protected transient int fIdCount;
0115:
0116: /** Identifier name indexes. */
0117: protected transient String fIdName[];
0118:
0119: /** Identifier element indexes. */
0120: protected transient int fIdElement[];
0121:
0122: /** DOM2: For namespace support in the deferred case.
0123: */
0124: // Implementation Note: The deferred element and attribute must know how to
0125: // interpret the int representing the qname.
0126: protected boolean fNamespacesEnabled = false;
0127:
0128: //
0129: // private data
0130: //
0131: private transient final StringBuffer fBufferStr = new StringBuffer();
0132: private transient final Vector fStrChunks = new Vector();
0133:
0134: //
0135: // Constructors
0136: //
0137:
0138: /**
0139: * NON-DOM: Actually creating a Document is outside the DOM's spec,
0140: * since it has to operate in terms of a particular implementation.
0141: */
0142: public DeferredDocumentImpl() {
0143: this (false);
0144: } // <init>()
0145:
0146: /**
0147: * NON-DOM: Actually creating a Document is outside the DOM's spec,
0148: * since it has to operate in terms of a particular implementation.
0149: */
0150: public DeferredDocumentImpl(boolean namespacesEnabled) {
0151: this (namespacesEnabled, false);
0152: } // <init>(boolean)
0153:
0154: /** Experimental constructor. */
0155: public DeferredDocumentImpl(boolean namespaces,
0156: boolean grammarAccess) {
0157: super (grammarAccess);
0158:
0159: needsSyncData(true);
0160: needsSyncChildren(true);
0161:
0162: fNamespacesEnabled = namespaces;
0163:
0164: } // <init>(boolean,boolean)
0165:
0166: //
0167: // Public methods
0168: //
0169:
0170: /**
0171: * Retrieve information describing the abilities of this particular
0172: * DOM implementation. Intended to support applications that may be
0173: * using DOMs retrieved from several different sources, potentially
0174: * with different underlying representations.
0175: */
0176: public DOMImplementation getImplementation() {
0177: // Currently implemented as a singleton, since it's hardcoded
0178: // information anyway.
0179: return DeferredDOMImplementationImpl.getDOMImplementation();
0180: }
0181:
0182: /** Returns the cached parser.getNamespaces() value.*/
0183: boolean getNamespacesEnabled() {
0184: return fNamespacesEnabled;
0185: }
0186:
0187: void setNamespacesEnabled(boolean enable) {
0188: fNamespacesEnabled = enable;
0189: }
0190:
0191: // internal factory methods
0192:
0193: /** Creates a document node in the table. */
0194: public int createDeferredDocument() {
0195: int nodeIndex = createNode(Node.DOCUMENT_NODE);
0196: return nodeIndex;
0197: }
0198:
0199: /** Creates a doctype. */
0200: public int createDeferredDocumentType(String rootElementName,
0201: String publicId, String systemId) {
0202:
0203: // create node
0204: int nodeIndex = createNode(Node.DOCUMENT_TYPE_NODE);
0205: int chunk = nodeIndex >> CHUNK_SHIFT;
0206: int index = nodeIndex & CHUNK_MASK;
0207:
0208: // save name, public id, system id
0209: setChunkValue(fNodeName, rootElementName, chunk, index);
0210: setChunkValue(fNodeValue, publicId, chunk, index);
0211: setChunkValue(fNodeURI, systemId, chunk, index);
0212:
0213: // return node index
0214: return nodeIndex;
0215:
0216: } // createDeferredDocumentType(String,String,String):int
0217:
0218: public void setInternalSubset(int doctypeIndex, String subset) {
0219: int chunk = doctypeIndex >> CHUNK_SHIFT;
0220: int index = doctypeIndex & CHUNK_MASK;
0221:
0222: // create extra data node to store internal subset
0223: int extraDataIndex = createNode(Node.DOCUMENT_TYPE_NODE);
0224: int echunk = extraDataIndex >> CHUNK_SHIFT;
0225: int eindex = extraDataIndex & CHUNK_MASK;
0226: setChunkIndex(fNodeExtra, extraDataIndex, chunk, index);
0227: setChunkValue(fNodeValue, subset, echunk, eindex);
0228: }
0229:
0230: /** Creates a notation in the table. */
0231: public int createDeferredNotation(String notationName,
0232: String publicId, String systemId, String baseURI) {
0233:
0234: // create node
0235: int nodeIndex = createNode(Node.NOTATION_NODE);
0236: int chunk = nodeIndex >> CHUNK_SHIFT;
0237: int index = nodeIndex & CHUNK_MASK;
0238:
0239: // create extra data node
0240: int extraDataIndex = createNode(Node.NOTATION_NODE);
0241: int echunk = extraDataIndex >> CHUNK_SHIFT;
0242: int eindex = extraDataIndex & CHUNK_MASK;
0243:
0244: // save name, public id, system id, and notation name
0245: setChunkValue(fNodeName, notationName, chunk, index);
0246: setChunkValue(fNodeValue, publicId, chunk, index);
0247: setChunkValue(fNodeURI, systemId, chunk, index);
0248:
0249: // in extra data node set baseURI value
0250: setChunkIndex(fNodeExtra, extraDataIndex, chunk, index);
0251: setChunkValue(fNodeName, baseURI, echunk, eindex);
0252:
0253: // return node index
0254: return nodeIndex;
0255:
0256: } // createDeferredNotation(String,String,String):int
0257:
0258: /** Creates an entity in the table. */
0259: public int createDeferredEntity(String entityName, String publicId,
0260: String systemId, String notationName, String baseURI) {
0261: // create node
0262: int nodeIndex = createNode(Node.ENTITY_NODE);
0263: int chunk = nodeIndex >> CHUNK_SHIFT;
0264: int index = nodeIndex & CHUNK_MASK;
0265:
0266: // create extra data node
0267: int extraDataIndex = createNode(Node.ENTITY_NODE);
0268: int echunk = extraDataIndex >> CHUNK_SHIFT;
0269: int eindex = extraDataIndex & CHUNK_MASK;
0270:
0271: // save name, public id, system id, and notation name
0272: setChunkValue(fNodeName, entityName, chunk, index);
0273: setChunkValue(fNodeValue, publicId, chunk, index);
0274: setChunkValue(fNodeURI, systemId, chunk, index);
0275: setChunkIndex(fNodeExtra, extraDataIndex, chunk, index);
0276: // set other values in the extra chunk
0277: // notation
0278: setChunkValue(fNodeName, notationName, echunk, eindex);
0279: // version L3
0280: setChunkValue(fNodeValue, null, echunk, eindex);
0281: // encoding L3
0282: setChunkValue(fNodeURI, null, echunk, eindex);
0283:
0284: int extraDataIndex2 = createNode(Node.ENTITY_NODE);
0285: int echunk2 = extraDataIndex2 >> CHUNK_SHIFT;
0286: int eindex2 = extraDataIndex2 & CHUNK_MASK;
0287:
0288: setChunkIndex(fNodeExtra, extraDataIndex2, echunk, eindex);
0289:
0290: // baseURI
0291: setChunkValue(fNodeName, baseURI, echunk2, eindex2);
0292:
0293: // return node index
0294: return nodeIndex;
0295:
0296: } // createDeferredEntity(String,String,String,String):int
0297:
0298: public String getDeferredEntityBaseURI(int entityIndex) {
0299: if (entityIndex != -1) {
0300: int extraDataIndex = getNodeExtra(entityIndex, false);
0301: extraDataIndex = getNodeExtra(extraDataIndex, false);
0302: return getNodeName(extraDataIndex, false);
0303: }
0304: return null;
0305: }
0306:
0307: // DOM Level 3: setting encoding and version
0308: public void setEntityInfo(int currentEntityDecl, String version,
0309: String encoding) {
0310: int eNodeIndex = getNodeExtra(currentEntityDecl, false);
0311: if (eNodeIndex != -1) {
0312: int echunk = eNodeIndex >> CHUNK_SHIFT;
0313: int eindex = eNodeIndex & CHUNK_MASK;
0314: setChunkValue(fNodeValue, version, echunk, eindex);
0315: setChunkValue(fNodeURI, encoding, echunk, eindex);
0316: }
0317: }
0318:
0319: // DOM Level 3: sets element TypeInfo
0320: public void setTypeInfo(int elementNodeIndex, Object type) {
0321: int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
0322: int elementIndex = elementNodeIndex & CHUNK_MASK;
0323: setChunkValue(fNodeValue, type, elementChunk, elementIndex);
0324: }
0325:
0326: /**
0327: * DOM Internal
0328: *
0329: * An attribute specifying the actual encoding of this document. This is
0330: * <code>null</code> otherwise.
0331: * <br> This attribute represents the property [character encoding scheme]
0332: * defined in .
0333: */
0334: public void setInputEncoding(int currentEntityDecl, String value) {
0335: // get first extra data chunk
0336: int nodeIndex = getNodeExtra(currentEntityDecl, false);
0337: // get second extra data chunk
0338: int extraDataIndex = getNodeExtra(nodeIndex, false);
0339:
0340: int echunk = extraDataIndex >> CHUNK_SHIFT;
0341: int eindex = extraDataIndex & CHUNK_MASK;
0342:
0343: setChunkValue(fNodeValue, value, echunk, eindex);
0344:
0345: }
0346:
0347: /** Creates an entity reference node in the table. */
0348: public int createDeferredEntityReference(String name, String baseURI) {
0349:
0350: // create node
0351: int nodeIndex = createNode(Node.ENTITY_REFERENCE_NODE);
0352: int chunk = nodeIndex >> CHUNK_SHIFT;
0353: int index = nodeIndex & CHUNK_MASK;
0354: setChunkValue(fNodeName, name, chunk, index);
0355: setChunkValue(fNodeValue, baseURI, chunk, index);
0356:
0357: // return node index
0358: return nodeIndex;
0359:
0360: } // createDeferredEntityReference(String):int
0361:
0362: /**
0363: * Creates an element node with a URI in the table and type information.
0364: * @deprecated
0365: */
0366: public int createDeferredElement(String elementURI,
0367: String elementName, Object type) {
0368:
0369: // create node
0370: int elementNodeIndex = createNode(Node.ELEMENT_NODE);
0371: int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
0372: int elementIndex = elementNodeIndex & CHUNK_MASK;
0373: setChunkValue(fNodeName, elementName, elementChunk,
0374: elementIndex);
0375: setChunkValue(fNodeURI, elementURI, elementChunk, elementIndex);
0376: setChunkValue(fNodeValue, type, elementChunk, elementIndex);
0377:
0378: // return node index
0379: return elementNodeIndex;
0380:
0381: } // createDeferredElement(String,String,Object):int
0382:
0383: /**
0384: * Creates an element node in the table.
0385: * @deprecated
0386: */
0387: public int createDeferredElement(String elementName) {
0388: return createDeferredElement(null, elementName);
0389: }
0390:
0391: /**
0392: * Creates an element node with a URI in the table.
0393: */
0394: public int createDeferredElement(String elementURI,
0395: String elementName) {
0396:
0397: // create node
0398: int elementNodeIndex = createNode(Node.ELEMENT_NODE);
0399: int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
0400: int elementIndex = elementNodeIndex & CHUNK_MASK;
0401: setChunkValue(fNodeName, elementName, elementChunk,
0402: elementIndex);
0403: setChunkValue(fNodeURI, elementURI, elementChunk, elementIndex);
0404:
0405: // return node index
0406: return elementNodeIndex;
0407:
0408: } // createDeferredElement(String,String):int
0409:
0410: /**
0411: * This method is used by the DOMParser to create attributes.
0412: * @param elementNodeIndex
0413: * @param attrName
0414: * @param attrURI
0415: * @param attrValue
0416: * @param specified
0417: * @param id
0418: * @param type
0419: * @return int
0420: */
0421: public int setDeferredAttribute(int elementNodeIndex,
0422: String attrName, String attrURI, String attrValue,
0423: boolean specified, boolean id, Object type) {
0424:
0425: // create attribute
0426: int attrNodeIndex = createDeferredAttribute(attrName, attrURI,
0427: attrValue, specified);
0428: int attrChunk = attrNodeIndex >> CHUNK_SHIFT;
0429: int attrIndex = attrNodeIndex & CHUNK_MASK;
0430: // set attribute's parent to element
0431: setChunkIndex(fNodeParent, elementNodeIndex, attrChunk,
0432: attrIndex);
0433:
0434: int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
0435: int elementIndex = elementNodeIndex & CHUNK_MASK;
0436:
0437: // get element's last attribute
0438: int lastAttrNodeIndex = getChunkIndex(fNodeExtra, elementChunk,
0439: elementIndex);
0440: if (lastAttrNodeIndex != 0) {
0441: // add link from new attribute to last attribute
0442: setChunkIndex(fNodePrevSib, lastAttrNodeIndex, attrChunk,
0443: attrIndex);
0444: }
0445: // add link from element to new last attribute
0446: setChunkIndex(fNodeExtra, attrNodeIndex, elementChunk,
0447: elementIndex);
0448:
0449: int extra = getChunkIndex(fNodeExtra, attrChunk, attrIndex);
0450: if (id) {
0451: extra = extra | ID;
0452: setChunkIndex(fNodeExtra, extra, attrChunk, attrIndex);
0453: String value = getChunkValue(fNodeValue, attrChunk,
0454: attrIndex);
0455: putIdentifier(value, elementNodeIndex);
0456: }
0457: // store type information
0458: if (type != null) {
0459: int extraDataIndex = createNode(DeferredNode.TYPE_NODE);
0460: int echunk = extraDataIndex >> CHUNK_SHIFT;
0461: int eindex = extraDataIndex & CHUNK_MASK;
0462:
0463: setChunkIndex(fNodeLastChild, extraDataIndex, attrChunk,
0464: attrIndex);
0465: setChunkValue(fNodeValue, type, echunk, eindex);
0466: }
0467:
0468: // return node index
0469: return attrNodeIndex;
0470: }
0471:
0472: /**
0473: * Sets an attribute on an element node.
0474: * @deprecated
0475: */
0476: public int setDeferredAttribute(int elementNodeIndex,
0477: String attrName, String attrURI, String attrValue,
0478: boolean specified) {
0479: // create attribute
0480: int attrNodeIndex = createDeferredAttribute(attrName, attrURI,
0481: attrValue, specified);
0482: int attrChunk = attrNodeIndex >> CHUNK_SHIFT;
0483: int attrIndex = attrNodeIndex & CHUNK_MASK;
0484: // set attribute's parent to element
0485: setChunkIndex(fNodeParent, elementNodeIndex, attrChunk,
0486: attrIndex);
0487:
0488: int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
0489: int elementIndex = elementNodeIndex & CHUNK_MASK;
0490:
0491: // get element's last attribute
0492: int lastAttrNodeIndex = getChunkIndex(fNodeExtra, elementChunk,
0493: elementIndex);
0494: if (lastAttrNodeIndex != 0) {
0495: // add link from new attribute to last attribute
0496: setChunkIndex(fNodePrevSib, lastAttrNodeIndex, attrChunk,
0497: attrIndex);
0498: }
0499: // add link from element to new last attribute
0500: setChunkIndex(fNodeExtra, attrNodeIndex, elementChunk,
0501: elementIndex);
0502:
0503: // return node index
0504: return attrNodeIndex;
0505:
0506: } // setDeferredAttribute(int,String,String,String,boolean):int
0507:
0508: /** Creates an attribute in the table. */
0509: public int createDeferredAttribute(String attrName,
0510: String attrValue, boolean specified) {
0511: return createDeferredAttribute(attrName, null, attrValue,
0512: specified);
0513: }
0514:
0515: /** Creates an attribute with a URI in the table. */
0516: public int createDeferredAttribute(String attrName, String attrURI,
0517: String attrValue, boolean specified) {
0518:
0519: // create node
0520: int nodeIndex = createNode(NodeImpl.ATTRIBUTE_NODE);
0521: int chunk = nodeIndex >> CHUNK_SHIFT;
0522: int index = nodeIndex & CHUNK_MASK;
0523: setChunkValue(fNodeName, attrName, chunk, index);
0524: setChunkValue(fNodeURI, attrURI, chunk, index);
0525: setChunkValue(fNodeValue, attrValue, chunk, index);
0526: int extra = specified ? SPECIFIED : 0;
0527: setChunkIndex(fNodeExtra, extra, chunk, index);
0528:
0529: // return node index
0530: return nodeIndex;
0531:
0532: } // createDeferredAttribute(String,String,String,boolean):int
0533:
0534: /** Creates an element definition in the table.*/
0535: public int createDeferredElementDefinition(String elementName) {
0536:
0537: // create node
0538: int nodeIndex = createNode(NodeImpl.ELEMENT_DEFINITION_NODE);
0539: int chunk = nodeIndex >> CHUNK_SHIFT;
0540: int index = nodeIndex & CHUNK_MASK;
0541: setChunkValue(fNodeName, elementName, chunk, index);
0542:
0543: // return node index
0544: return nodeIndex;
0545:
0546: } // createDeferredElementDefinition(String):int
0547:
0548: /** Creates a text node in the table. */
0549: public int createDeferredTextNode(String data,
0550: boolean ignorableWhitespace) {
0551:
0552: // create node
0553: int nodeIndex = createNode(Node.TEXT_NODE);
0554: int chunk = nodeIndex >> CHUNK_SHIFT;
0555: int index = nodeIndex & CHUNK_MASK;
0556: setChunkValue(fNodeValue, data, chunk, index);
0557: // use extra to store ignorableWhitespace info
0558: setChunkIndex(fNodeExtra, ignorableWhitespace ? 1 : 0, chunk,
0559: index);
0560:
0561: // return node index
0562: return nodeIndex;
0563:
0564: } // createDeferredTextNode(String,boolean):int
0565:
0566: /** Creates a CDATA section node in the table. */
0567: public int createDeferredCDATASection(String data) {
0568:
0569: // create node
0570: int nodeIndex = createNode(Node.CDATA_SECTION_NODE);
0571: int chunk = nodeIndex >> CHUNK_SHIFT;
0572: int index = nodeIndex & CHUNK_MASK;
0573: setChunkValue(fNodeValue, data, chunk, index);
0574:
0575: // return node index
0576: return nodeIndex;
0577:
0578: } // createDeferredCDATASection(String):int
0579:
0580: /** Creates a processing instruction node in the table. */
0581: public int createDeferredProcessingInstruction(String target,
0582: String data) {
0583: // create node
0584: int nodeIndex = createNode(Node.PROCESSING_INSTRUCTION_NODE);
0585: int chunk = nodeIndex >> CHUNK_SHIFT;
0586: int index = nodeIndex & CHUNK_MASK;
0587: setChunkValue(fNodeName, target, chunk, index);
0588: setChunkValue(fNodeValue, data, chunk, index);
0589: // return node index
0590: return nodeIndex;
0591:
0592: } // createDeferredProcessingInstruction(String,String):int
0593:
0594: /** Creates a comment node in the table. */
0595: public int createDeferredComment(String data) {
0596:
0597: // create node
0598: int nodeIndex = createNode(Node.COMMENT_NODE);
0599: int chunk = nodeIndex >> CHUNK_SHIFT;
0600: int index = nodeIndex & CHUNK_MASK;
0601: setChunkValue(fNodeValue, data, chunk, index);
0602:
0603: // return node index
0604: return nodeIndex;
0605:
0606: } // createDeferredComment(String):int
0607:
0608: /** Creates a clone of the specified node. */
0609: public int cloneNode(int nodeIndex, boolean deep) {
0610:
0611: // clone immediate node
0612:
0613: int nchunk = nodeIndex >> CHUNK_SHIFT;
0614: int nindex = nodeIndex & CHUNK_MASK;
0615: int nodeType = fNodeType[nchunk][nindex];
0616: int cloneIndex = createNode((short) nodeType);
0617: int cchunk = cloneIndex >> CHUNK_SHIFT;
0618: int cindex = cloneIndex & CHUNK_MASK;
0619: setChunkValue(fNodeName, fNodeName[nchunk][nindex], cchunk,
0620: cindex);
0621: setChunkValue(fNodeValue, fNodeValue[nchunk][nindex], cchunk,
0622: cindex);
0623: setChunkValue(fNodeURI, fNodeURI[nchunk][nindex], cchunk,
0624: cindex);
0625: int extraIndex = fNodeExtra[nchunk][nindex];
0626: if (extraIndex != -1) {
0627: if (nodeType != Node.ATTRIBUTE_NODE
0628: && nodeType != Node.TEXT_NODE) {
0629: extraIndex = cloneNode(extraIndex, false);
0630: }
0631: setChunkIndex(fNodeExtra, extraIndex, cchunk, cindex);
0632: }
0633:
0634: // clone and attach children
0635: if (deep) {
0636: int prevIndex = -1;
0637: int childIndex = getLastChild(nodeIndex, false);
0638: while (childIndex != -1) {
0639: int clonedChildIndex = cloneNode(childIndex, deep);
0640: insertBefore(cloneIndex, clonedChildIndex, prevIndex);
0641: prevIndex = clonedChildIndex;
0642: childIndex = getRealPrevSibling(childIndex, false);
0643: }
0644:
0645: }
0646:
0647: // return cloned node index
0648: return cloneIndex;
0649:
0650: } // cloneNode(int,boolean):int
0651:
0652: /** Appends a child to the specified parent in the table. */
0653: public void appendChild(int parentIndex, int childIndex) {
0654:
0655: // append parent index
0656: int pchunk = parentIndex >> CHUNK_SHIFT;
0657: int pindex = parentIndex & CHUNK_MASK;
0658: int cchunk = childIndex >> CHUNK_SHIFT;
0659: int cindex = childIndex & CHUNK_MASK;
0660: setChunkIndex(fNodeParent, parentIndex, cchunk, cindex);
0661:
0662: // set previous sibling of new child
0663: int olast = getChunkIndex(fNodeLastChild, pchunk, pindex);
0664: setChunkIndex(fNodePrevSib, olast, cchunk, cindex);
0665:
0666: // update parent's last child
0667: setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex);
0668:
0669: } // appendChild(int,int)
0670:
0671: /** Adds an attribute node to the specified element. */
0672: public int setAttributeNode(int elemIndex, int attrIndex) {
0673:
0674: int echunk = elemIndex >> CHUNK_SHIFT;
0675: int eindex = elemIndex & CHUNK_MASK;
0676: int achunk = attrIndex >> CHUNK_SHIFT;
0677: int aindex = attrIndex & CHUNK_MASK;
0678:
0679: // see if this attribute is already here
0680: String attrName = getChunkValue(fNodeName, achunk, aindex);
0681: int oldAttrIndex = getChunkIndex(fNodeExtra, echunk, eindex);
0682: int nextIndex = -1;
0683: int oachunk = -1;
0684: int oaindex = -1;
0685: while (oldAttrIndex != -1) {
0686: oachunk = oldAttrIndex >> CHUNK_SHIFT;
0687: oaindex = oldAttrIndex & CHUNK_MASK;
0688: String oldAttrName = getChunkValue(fNodeName, oachunk,
0689: oaindex);
0690: if (oldAttrName.equals(attrName)) {
0691: break;
0692: }
0693: nextIndex = oldAttrIndex;
0694: oldAttrIndex = getChunkIndex(fNodePrevSib, oachunk, oaindex);
0695: }
0696:
0697: // remove old attribute
0698: if (oldAttrIndex != -1) {
0699:
0700: // patch links
0701: int prevIndex = getChunkIndex(fNodePrevSib, oachunk,
0702: oaindex);
0703: if (nextIndex == -1) {
0704: setChunkIndex(fNodeExtra, prevIndex, echunk, eindex);
0705: } else {
0706: int pchunk = nextIndex >> CHUNK_SHIFT;
0707: int pindex = nextIndex & CHUNK_MASK;
0708: setChunkIndex(fNodePrevSib, prevIndex, pchunk, pindex);
0709: }
0710:
0711: // remove connections to siblings
0712: clearChunkIndex(fNodeType, oachunk, oaindex);
0713: clearChunkValue(fNodeName, oachunk, oaindex);
0714: clearChunkValue(fNodeValue, oachunk, oaindex);
0715: clearChunkIndex(fNodeParent, oachunk, oaindex);
0716: clearChunkIndex(fNodePrevSib, oachunk, oaindex);
0717: int attrTextIndex = clearChunkIndex(fNodeLastChild,
0718: oachunk, oaindex);
0719: int atchunk = attrTextIndex >> CHUNK_SHIFT;
0720: int atindex = attrTextIndex & CHUNK_MASK;
0721: clearChunkIndex(fNodeType, atchunk, atindex);
0722: clearChunkValue(fNodeValue, atchunk, atindex);
0723: clearChunkIndex(fNodeParent, atchunk, atindex);
0724: clearChunkIndex(fNodeLastChild, atchunk, atindex);
0725: }
0726:
0727: // add new attribute
0728: int prevIndex = getChunkIndex(fNodeExtra, echunk, eindex);
0729: setChunkIndex(fNodeExtra, attrIndex, echunk, eindex);
0730: setChunkIndex(fNodePrevSib, prevIndex, achunk, aindex);
0731:
0732: // return
0733: return oldAttrIndex;
0734:
0735: } // setAttributeNode(int,int):int
0736:
0737: /** Adds an attribute node to the specified element. */
0738: public void setIdAttributeNode(int elemIndex, int attrIndex) {
0739:
0740: int chunk = attrIndex >> CHUNK_SHIFT;
0741: int index = attrIndex & CHUNK_MASK;
0742: int extra = getChunkIndex(fNodeExtra, chunk, index);
0743: extra = extra | ID;
0744: setChunkIndex(fNodeExtra, extra, chunk, index);
0745:
0746: String value = getChunkValue(fNodeValue, chunk, index);
0747: putIdentifier(value, elemIndex);
0748: }
0749:
0750: /** Sets type of attribute */
0751: public void setIdAttribute(int attrIndex) {
0752:
0753: int chunk = attrIndex >> CHUNK_SHIFT;
0754: int index = attrIndex & CHUNK_MASK;
0755: int extra = getChunkIndex(fNodeExtra, chunk, index);
0756: extra = extra | ID;
0757: setChunkIndex(fNodeExtra, extra, chunk, index);
0758: }
0759:
0760: /** Inserts a child before the specified node in the table. */
0761: public int insertBefore(int parentIndex, int newChildIndex,
0762: int refChildIndex) {
0763:
0764: if (refChildIndex == -1) {
0765: appendChild(parentIndex, newChildIndex);
0766: return newChildIndex;
0767: }
0768:
0769: int nchunk = newChildIndex >> CHUNK_SHIFT;
0770: int nindex = newChildIndex & CHUNK_MASK;
0771: int rchunk = refChildIndex >> CHUNK_SHIFT;
0772: int rindex = refChildIndex & CHUNK_MASK;
0773: int previousIndex = getChunkIndex(fNodePrevSib, rchunk, rindex);
0774: setChunkIndex(fNodePrevSib, newChildIndex, rchunk, rindex);
0775: setChunkIndex(fNodePrevSib, previousIndex, nchunk, nindex);
0776:
0777: return newChildIndex;
0778:
0779: } // insertBefore(int,int,int):int
0780:
0781: /** Sets the last child of the parentIndex to childIndex. */
0782: public void setAsLastChild(int parentIndex, int childIndex) {
0783: int pchunk = parentIndex >> CHUNK_SHIFT;
0784: int pindex = parentIndex & CHUNK_MASK;
0785: setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex);
0786: } // setAsLastChild(int,int)
0787:
0788: /**
0789: * Returns the parent node of the given node.
0790: * <em>Calling this method does not free the parent index.</em>
0791: */
0792: public int getParentNode(int nodeIndex) {
0793: return getParentNode(nodeIndex, false);
0794: }
0795:
0796: /**
0797: * Returns the parent node of the given node.
0798: * @param free True to free parent node.
0799: */
0800: public int getParentNode(int nodeIndex, boolean free) {
0801:
0802: if (nodeIndex == -1) {
0803: return -1;
0804: }
0805:
0806: int chunk = nodeIndex >> CHUNK_SHIFT;
0807: int index = nodeIndex & CHUNK_MASK;
0808: return free ? clearChunkIndex(fNodeParent, chunk, index)
0809: : getChunkIndex(fNodeParent, chunk, index);
0810:
0811: } // getParentNode(int):int
0812:
0813: /** Returns the last child of the given node. */
0814: public int getLastChild(int nodeIndex) {
0815: return getLastChild(nodeIndex, true);
0816: }
0817:
0818: /**
0819: * Returns the last child of the given node.
0820: * @param free True to free child index.
0821: */
0822: public int getLastChild(int nodeIndex, boolean free) {
0823:
0824: if (nodeIndex == -1) {
0825: return -1;
0826: }
0827:
0828: int chunk = nodeIndex >> CHUNK_SHIFT;
0829: int index = nodeIndex & CHUNK_MASK;
0830: return free ? clearChunkIndex(fNodeLastChild, chunk, index)
0831: : getChunkIndex(fNodeLastChild, chunk, index);
0832:
0833: } // getLastChild(int,boolean):int
0834:
0835: /**
0836: * Returns the prev sibling of the given node.
0837: * This is post-normalization of Text Nodes.
0838: */
0839: public int getPrevSibling(int nodeIndex) {
0840: return getPrevSibling(nodeIndex, true);
0841: }
0842:
0843: /**
0844: * Returns the prev sibling of the given node.
0845: * @param free True to free sibling index.
0846: */
0847: public int getPrevSibling(int nodeIndex, boolean free) {
0848:
0849: if (nodeIndex == -1) {
0850: return -1;
0851: }
0852:
0853: int chunk = nodeIndex >> CHUNK_SHIFT;
0854: int index = nodeIndex & CHUNK_MASK;
0855: int type = getChunkIndex(fNodeType, chunk, index);
0856: if (type == Node.TEXT_NODE) {
0857: do {
0858: nodeIndex = getChunkIndex(fNodePrevSib, chunk, index);
0859: if (nodeIndex == -1) {
0860: break;
0861: }
0862: chunk = nodeIndex >> CHUNK_SHIFT;
0863: index = nodeIndex & CHUNK_MASK;
0864: type = getChunkIndex(fNodeType, chunk, index);
0865: } while (type == Node.TEXT_NODE);
0866: } else {
0867: nodeIndex = getChunkIndex(fNodePrevSib, chunk, index);
0868: }
0869:
0870: return nodeIndex;
0871:
0872: } // getPrevSibling(int,boolean):int
0873:
0874: /**
0875: * Returns the <i>real</i> prev sibling of the given node,
0876: * directly from the data structures. Used by TextImpl#getNodeValue()
0877: * to normalize values.
0878: */
0879: public int getRealPrevSibling(int nodeIndex) {
0880: return getRealPrevSibling(nodeIndex, true);
0881: }
0882:
0883: /**
0884: * Returns the <i>real</i> prev sibling of the given node.
0885: * @param free True to free sibling index.
0886: */
0887: public int getRealPrevSibling(int nodeIndex, boolean free) {
0888:
0889: if (nodeIndex == -1) {
0890: return -1;
0891: }
0892:
0893: int chunk = nodeIndex >> CHUNK_SHIFT;
0894: int index = nodeIndex & CHUNK_MASK;
0895: return free ? clearChunkIndex(fNodePrevSib, chunk, index)
0896: : getChunkIndex(fNodePrevSib, chunk, index);
0897:
0898: } // getReadPrevSibling(int,boolean):int
0899:
0900: /**
0901: * Returns the index of the element definition in the table
0902: * with the specified name index, or -1 if no such definition
0903: * exists.
0904: */
0905: public int lookupElementDefinition(String elementName) {
0906:
0907: if (fNodeCount > 1) {
0908:
0909: // find doctype
0910: int docTypeIndex = -1;
0911: int nchunk = 0;
0912: int nindex = 0;
0913: for (int index = getChunkIndex(fNodeLastChild, nchunk,
0914: nindex); index != -1; index = getChunkIndex(
0915: fNodePrevSib, nchunk, nindex)) {
0916:
0917: nchunk = index >> CHUNK_SHIFT;
0918: nindex = index & CHUNK_MASK;
0919: if (getChunkIndex(fNodeType, nchunk, nindex) == Node.DOCUMENT_TYPE_NODE) {
0920: docTypeIndex = index;
0921: break;
0922: }
0923: }
0924:
0925: // find element definition
0926: if (docTypeIndex == -1) {
0927: return -1;
0928: }
0929: nchunk = docTypeIndex >> CHUNK_SHIFT;
0930: nindex = docTypeIndex & CHUNK_MASK;
0931: for (int index = getChunkIndex(fNodeLastChild, nchunk,
0932: nindex); index != -1; index = getChunkIndex(
0933: fNodePrevSib, nchunk, nindex)) {
0934:
0935: nchunk = index >> CHUNK_SHIFT;
0936: nindex = index & CHUNK_MASK;
0937: if (getChunkIndex(fNodeType, nchunk, nindex) == NodeImpl.ELEMENT_DEFINITION_NODE
0938: && getChunkValue(fNodeName, nchunk, nindex) == elementName) {
0939: return index;
0940: }
0941: }
0942: }
0943:
0944: return -1;
0945:
0946: } // lookupElementDefinition(String):int
0947:
0948: /** Instantiates the requested node object. */
0949: public DeferredNode getNodeObject(int nodeIndex) {
0950:
0951: // is there anything to do?
0952: if (nodeIndex == -1) {
0953: return null;
0954: }
0955:
0956: // get node type
0957: int chunk = nodeIndex >> CHUNK_SHIFT;
0958: int index = nodeIndex & CHUNK_MASK;
0959: int type = getChunkIndex(fNodeType, chunk, index);
0960: if (type != Node.TEXT_NODE && type != Node.CDATA_SECTION_NODE) {
0961: clearChunkIndex(fNodeType, chunk, index);
0962: }
0963:
0964: // create new node
0965: DeferredNode node = null;
0966: switch (type) {
0967:
0968: //
0969: // Standard DOM node types
0970: //
0971:
0972: case Node.ATTRIBUTE_NODE: {
0973: if (fNamespacesEnabled) {
0974: node = new DeferredAttrNSImpl(this , nodeIndex);
0975: } else {
0976: node = new DeferredAttrImpl(this , nodeIndex);
0977: }
0978: break;
0979: }
0980:
0981: case Node.CDATA_SECTION_NODE: {
0982: node = new DeferredCDATASectionImpl(this , nodeIndex);
0983: break;
0984: }
0985:
0986: case Node.COMMENT_NODE: {
0987: node = new DeferredCommentImpl(this , nodeIndex);
0988: break;
0989: }
0990:
0991: // NOTE: Document fragments can never be "fast".
0992: //
0993: // The parser will never ask to create a document
0994: // fragment during the parse. Document fragments
0995: // are used by the application *after* the parse.
0996: //
0997: // case Node.DOCUMENT_FRAGMENT_NODE: { break; }
0998: case Node.DOCUMENT_NODE: {
0999: // this node is never "fast"
1000: node = this ;
1001: break;
1002: }
1003:
1004: case Node.DOCUMENT_TYPE_NODE: {
1005: node = new DeferredDocumentTypeImpl(this , nodeIndex);
1006: // save the doctype node
1007: docType = (DocumentTypeImpl) node;
1008: break;
1009: }
1010:
1011: case Node.ELEMENT_NODE: {
1012:
1013: if (DEBUG_IDS) {
1014: System.out.println("getNodeObject(ELEMENT_NODE): "
1015: + nodeIndex);
1016: }
1017:
1018: // create node
1019: if (fNamespacesEnabled) {
1020: node = new DeferredElementNSImpl(this , nodeIndex);
1021: } else {
1022: node = new DeferredElementImpl(this , nodeIndex);
1023: }
1024:
1025: // check to see if this element needs to be
1026: // registered for its ID attributes
1027: if (fIdElement != null) {
1028: int idIndex = binarySearch(fIdElement, 0, fIdCount - 1,
1029: nodeIndex);
1030: while (idIndex != -1) {
1031:
1032: if (DEBUG_IDS) {
1033: System.out.println(" id index: " + idIndex);
1034: System.out.println(" fIdName[" + idIndex
1035: + "]: " + fIdName[idIndex]);
1036: }
1037:
1038: // register ID
1039: String name = fIdName[idIndex];
1040: if (name != null) {
1041: if (DEBUG_IDS) {
1042: System.out.println(" name: " + name);
1043: System.out.print("getNodeObject()#");
1044: }
1045: putIdentifier0(name, (Element) node);
1046: fIdName[idIndex] = null;
1047: }
1048:
1049: // continue if there are more IDs for
1050: // this element
1051: if (idIndex + 1 < fIdCount
1052: && fIdElement[idIndex + 1] == nodeIndex) {
1053: idIndex++;
1054: } else {
1055: idIndex = -1;
1056: }
1057: }
1058: }
1059: break;
1060: }
1061:
1062: case Node.ENTITY_NODE: {
1063: node = new DeferredEntityImpl(this , nodeIndex);
1064: break;
1065: }
1066:
1067: case Node.ENTITY_REFERENCE_NODE: {
1068: node = new DeferredEntityReferenceImpl(this , nodeIndex);
1069: break;
1070: }
1071:
1072: case Node.NOTATION_NODE: {
1073: node = new DeferredNotationImpl(this , nodeIndex);
1074: break;
1075: }
1076:
1077: case Node.PROCESSING_INSTRUCTION_NODE: {
1078: node = new DeferredProcessingInstructionImpl(this ,
1079: nodeIndex);
1080: break;
1081: }
1082:
1083: case Node.TEXT_NODE: {
1084: node = new DeferredTextImpl(this , nodeIndex);
1085: break;
1086: }
1087:
1088: //
1089: // non-standard DOM node types
1090: //
1091:
1092: case NodeImpl.ELEMENT_DEFINITION_NODE: {
1093: node = new DeferredElementDefinitionImpl(this , nodeIndex);
1094: break;
1095: }
1096:
1097: default: {
1098: throw new IllegalArgumentException("type: " + type);
1099: }
1100:
1101: } // switch node type
1102:
1103: // store and return
1104: if (node != null) {
1105: return node;
1106: }
1107:
1108: // error
1109: throw new IllegalArgumentException();
1110:
1111: } // createNodeObject(int):Node
1112:
1113: /** Returns the name of the given node. */
1114: public String getNodeName(int nodeIndex) {
1115: return getNodeName(nodeIndex, true);
1116: } // getNodeNameString(int):String
1117:
1118: /**
1119: * Returns the name of the given node.
1120: * @param free True to free the string index.
1121: */
1122: public String getNodeName(int nodeIndex, boolean free) {
1123:
1124: if (nodeIndex == -1) {
1125: return null;
1126: }
1127:
1128: int chunk = nodeIndex >> CHUNK_SHIFT;
1129: int index = nodeIndex & CHUNK_MASK;
1130: return free ? clearChunkValue(fNodeName, chunk, index)
1131: : getChunkValue(fNodeName, chunk, index);
1132:
1133: } // getNodeName(int,boolean):String
1134:
1135: /** Returns the real value of the given node. */
1136: public String getNodeValueString(int nodeIndex) {
1137: return getNodeValueString(nodeIndex, true);
1138: } // getNodeValueString(int):String
1139:
1140: /**
1141: * Returns the real value of the given node.
1142: * @param free True to free the string index.
1143: */
1144: public String getNodeValueString(int nodeIndex, boolean free) {
1145:
1146: if (nodeIndex == -1) {
1147: return null;
1148: }
1149:
1150: int chunk = nodeIndex >> CHUNK_SHIFT;
1151: int index = nodeIndex & CHUNK_MASK;
1152: String value = free ? clearChunkValue(fNodeValue, chunk, index)
1153: : getChunkValue(fNodeValue, chunk, index);
1154: if (value == null) {
1155: return null;
1156: }
1157:
1158: int type = getChunkIndex(fNodeType, chunk, index);
1159: if (type == Node.TEXT_NODE) {
1160: int prevSib = getRealPrevSibling(nodeIndex);
1161: if (prevSib != -1
1162: && getNodeType(prevSib, false) == Node.TEXT_NODE) {
1163: // append data that is stored in fNodeValue
1164: // REVISIT: for text nodes it works differently than for CDATA
1165: // nodes.
1166: fStrChunks.addElement(value);
1167: do {
1168: // go in reverse order: find last child, then
1169: // its previous sibling, etc
1170: chunk = prevSib >> CHUNK_SHIFT;
1171: index = prevSib & CHUNK_MASK;
1172: value = getChunkValue(fNodeValue, chunk, index);
1173: fStrChunks.addElement(value);
1174: prevSib = getChunkIndex(fNodePrevSib, chunk, index);
1175: if (prevSib == -1) {
1176: break;
1177: }
1178: } while (getNodeType(prevSib, false) == Node.TEXT_NODE);
1179:
1180: int chunkCount = fStrChunks.size();
1181:
1182: // add to the buffer in the correct order.
1183: for (int i = chunkCount - 1; i >= 0; i--) {
1184: fBufferStr.append((String) fStrChunks.elementAt(i));
1185: }
1186:
1187: value = fBufferStr.toString();
1188: fStrChunks.removeAllElements();
1189: fBufferStr.setLength(0);
1190: return value;
1191: }
1192: } else if (type == Node.CDATA_SECTION_NODE) {
1193: // find if any other data stored in children
1194: int child = getLastChild(nodeIndex, false);
1195: if (child != -1) {
1196: // append data that is stored in fNodeValue
1197: fBufferStr.append(value);
1198: while (child != -1) {
1199: // go in reverse order: find last child, then
1200: // its previous sibling, etc
1201: chunk = child >> CHUNK_SHIFT;
1202: index = child & CHUNK_MASK;
1203: value = getChunkValue(fNodeValue, chunk, index);
1204: fStrChunks.addElement(value);
1205: child = getChunkIndex(fNodePrevSib, chunk, index);
1206: }
1207: // add to the buffer in the correct order.
1208: for (int i = fStrChunks.size() - 1; i >= 0; i--) {
1209: fBufferStr.append((String) fStrChunks.elementAt(i));
1210: }
1211:
1212: value = fBufferStr.toString();
1213: fStrChunks.setSize(0);
1214: fBufferStr.setLength(0);
1215: return value;
1216: }
1217: }
1218:
1219: return value;
1220:
1221: } // getNodeValueString(int,boolean):String
1222:
1223: /**
1224: * Returns the value of the given node.
1225: */
1226: public String getNodeValue(int nodeIndex) {
1227: return getNodeValue(nodeIndex, true);
1228: }
1229:
1230: /**
1231: * Clears the type info that is stored in the fNodeValue array
1232: * @param nodeIndex
1233: * @return Object - type information for the attribute/element node
1234: */
1235: public Object getTypeInfo(int nodeIndex) {
1236: if (nodeIndex == -1) {
1237: return null;
1238: }
1239:
1240: int chunk = nodeIndex >> CHUNK_SHIFT;
1241: int index = nodeIndex & CHUNK_MASK;
1242:
1243: Object value = fNodeValue[chunk] != null ? fNodeValue[chunk][index]
1244: : null;
1245: if (value != null) {
1246: fNodeValue[chunk][index] = null;
1247: RefCount c = (RefCount) fNodeValue[chunk][CHUNK_SIZE];
1248: c.fCount--;
1249: if (c.fCount == 0) {
1250: fNodeValue[chunk] = null;
1251: }
1252: }
1253: return value;
1254: }
1255:
1256: /**
1257: * Returns the value of the given node.
1258: * @param free True to free the value index.
1259: */
1260: public String getNodeValue(int nodeIndex, boolean free) {
1261:
1262: if (nodeIndex == -1) {
1263: return null;
1264: }
1265:
1266: int chunk = nodeIndex >> CHUNK_SHIFT;
1267: int index = nodeIndex & CHUNK_MASK;
1268: return free ? clearChunkValue(fNodeValue, chunk, index)
1269: : getChunkValue(fNodeValue, chunk, index);
1270:
1271: } // getNodeValue(int,boolean):String
1272:
1273: /**
1274: * Returns the extra info of the given node.
1275: * Used by AttrImpl to store specified value (1 == true).
1276: */
1277: public int getNodeExtra(int nodeIndex) {
1278: return getNodeExtra(nodeIndex, true);
1279: }
1280:
1281: /**
1282: * Returns the extra info of the given node.
1283: * @param free True to free the value index.
1284: */
1285: public int getNodeExtra(int nodeIndex, boolean free) {
1286:
1287: if (nodeIndex == -1) {
1288: return -1;
1289: }
1290:
1291: int chunk = nodeIndex >> CHUNK_SHIFT;
1292: int index = nodeIndex & CHUNK_MASK;
1293: return free ? clearChunkIndex(fNodeExtra, chunk, index)
1294: : getChunkIndex(fNodeExtra, chunk, index);
1295:
1296: } // getNodeExtra(int,boolean):int
1297:
1298: /** Returns the type of the given node. */
1299: public short getNodeType(int nodeIndex) {
1300: return getNodeType(nodeIndex, true);
1301: }
1302:
1303: /**
1304: * Returns the type of the given node.
1305: * @param free True to free type index.
1306: */
1307: public short getNodeType(int nodeIndex, boolean free) {
1308:
1309: if (nodeIndex == -1) {
1310: return -1;
1311: }
1312:
1313: int chunk = nodeIndex >> CHUNK_SHIFT;
1314: int index = nodeIndex & CHUNK_MASK;
1315: return free ? (short) clearChunkIndex(fNodeType, chunk, index)
1316: : (short) getChunkIndex(fNodeType, chunk, index);
1317:
1318: } // getNodeType(int):int
1319:
1320: /** Returns the attribute value of the given name. */
1321: public String getAttribute(int elemIndex, String name) {
1322: if (elemIndex == -1 || name == null) {
1323: return null;
1324: }
1325: int echunk = elemIndex >> CHUNK_SHIFT;
1326: int eindex = elemIndex & CHUNK_MASK;
1327: int attrIndex = getChunkIndex(fNodeExtra, echunk, eindex);
1328: while (attrIndex != -1) {
1329: int achunk = attrIndex >> CHUNK_SHIFT;
1330: int aindex = attrIndex & CHUNK_MASK;
1331: if (getChunkValue(fNodeName, achunk, aindex) == name) {
1332: return getChunkValue(fNodeValue, achunk, aindex);
1333: }
1334: attrIndex = getChunkIndex(fNodePrevSib, achunk, aindex);
1335: }
1336: return null;
1337: }
1338:
1339: /** Returns the URI of the given node. */
1340: public String getNodeURI(int nodeIndex) {
1341: return getNodeURI(nodeIndex, true);
1342: }
1343:
1344: /**
1345: * Returns the URI of the given node.
1346: * @param free True to free URI index.
1347: */
1348: public String getNodeURI(int nodeIndex, boolean free) {
1349:
1350: if (nodeIndex == -1) {
1351: return null;
1352: }
1353:
1354: int chunk = nodeIndex >> CHUNK_SHIFT;
1355: int index = nodeIndex & CHUNK_MASK;
1356: return free ? clearChunkValue(fNodeURI, chunk, index)
1357: : getChunkValue(fNodeURI, chunk, index);
1358:
1359: } // getNodeURI(int,int):String
1360:
1361: // identifier maintenance
1362:
1363: /** Registers an identifier name with a specified element node. */
1364: public void putIdentifier(String name, int elementNodeIndex) {
1365:
1366: if (DEBUG_IDS) {
1367: System.out.println("putIdentifier("
1368: + name
1369: + ", "
1370: + elementNodeIndex
1371: + ')'
1372: + " // "
1373: + getChunkValue(fNodeName,
1374: elementNodeIndex >> CHUNK_SHIFT,
1375: elementNodeIndex & CHUNK_MASK));
1376: }
1377:
1378: // initialize arrays
1379: if (fIdName == null) {
1380: fIdName = new String[64];
1381: fIdElement = new int[64];
1382: }
1383:
1384: // resize arrays
1385: if (fIdCount == fIdName.length) {
1386: String idName[] = new String[fIdCount * 2];
1387: System.arraycopy(fIdName, 0, idName, 0, fIdCount);
1388: fIdName = idName;
1389:
1390: int idElement[] = new int[idName.length];
1391: System.arraycopy(fIdElement, 0, idElement, 0, fIdCount);
1392: fIdElement = idElement;
1393: }
1394:
1395: // store identifier
1396: fIdName[fIdCount] = name;
1397: fIdElement[fIdCount] = elementNodeIndex;
1398: fIdCount++;
1399:
1400: } // putIdentifier(String,int)
1401:
1402: //
1403: // DEBUG
1404: //
1405:
1406: /** Prints out the tables. */
1407: public void print() {
1408:
1409: if (DEBUG_PRINT_REF_COUNTS) {
1410: System.out.print("num\t");
1411: System.out.print("type\t");
1412: System.out.print("name\t");
1413: System.out.print("val\t");
1414: System.out.print("par\t");
1415: System.out.print("lch\t");
1416: System.out.print("psib");
1417: System.out.println();
1418: for (int i = 0; i < fNodeType.length; i++) {
1419: if (fNodeType[i] != null) {
1420: // separator
1421: System.out.print("--------");
1422: System.out.print("--------");
1423: System.out.print("--------");
1424: System.out.print("--------");
1425: System.out.print("--------");
1426: System.out.print("--------");
1427: System.out.print("--------");
1428: System.out.println();
1429:
1430: // ref count
1431: System.out.print(i);
1432: System.out.print('\t');
1433: switch (fNodeType[i][CHUNK_SIZE]) {
1434: case DocumentImpl.ELEMENT_DEFINITION_NODE: {
1435: System.out.print("EDef");
1436: break;
1437: }
1438: case Node.DOCUMENT_NODE: {
1439: System.out.print("Doc");
1440: break;
1441: }
1442: case Node.DOCUMENT_TYPE_NODE: {
1443: System.out.print("DType");
1444: break;
1445: }
1446: case Node.COMMENT_NODE: {
1447: System.out.print("Com");
1448: break;
1449: }
1450: case Node.PROCESSING_INSTRUCTION_NODE: {
1451: System.out.print("PI");
1452: break;
1453: }
1454: case Node.ELEMENT_NODE: {
1455: System.out.print("Elem");
1456: break;
1457: }
1458: case Node.ENTITY_NODE: {
1459: System.out.print("Ent");
1460: break;
1461: }
1462: case Node.ENTITY_REFERENCE_NODE: {
1463: System.out.print("ERef");
1464: break;
1465: }
1466: case Node.TEXT_NODE: {
1467: System.out.print("Text");
1468: break;
1469: }
1470: case Node.ATTRIBUTE_NODE: {
1471: System.out.print("Attr");
1472: break;
1473: }
1474: case DeferredNode.TYPE_NODE: {
1475: System.out.print("TypeInfo");
1476: break;
1477: }
1478: default: {
1479: System.out
1480: .print("?" + fNodeType[i][CHUNK_SIZE]);
1481: }
1482: }
1483: System.out.print('\t');
1484: System.out.print(fNodeName[i][CHUNK_SIZE]);
1485: System.out.print('\t');
1486: System.out.print(fNodeValue[i][CHUNK_SIZE]);
1487: System.out.print('\t');
1488: System.out.print(fNodeURI[i][CHUNK_SIZE]);
1489: System.out.print('\t');
1490: System.out.print(fNodeParent[i][CHUNK_SIZE]);
1491: System.out.print('\t');
1492: System.out.print(fNodeLastChild[i][CHUNK_SIZE]);
1493: System.out.print('\t');
1494: System.out.print(fNodePrevSib[i][CHUNK_SIZE]);
1495: System.out.print('\t');
1496: System.out.print(fNodeExtra[i][CHUNK_SIZE]);
1497: System.out.println();
1498: }
1499: }
1500: }
1501:
1502: if (DEBUG_PRINT_TABLES) {
1503: // This assumes that the document is small
1504: System.out.println("# start table");
1505: for (int i = 0; i < fNodeCount; i++) {
1506: int chunk = i >> CHUNK_SHIFT;
1507: int index = i & CHUNK_MASK;
1508: if (i % 10 == 0) {
1509: System.out.print("num\t");
1510: System.out.print("type\t");
1511: System.out.print("name\t");
1512: System.out.print("val\t");
1513: System.out.print("uri\t");
1514: System.out.print("par\t");
1515: System.out.print("lch\t");
1516: System.out.print("psib\t");
1517: System.out.print("xtra");
1518: System.out.println();
1519: }
1520: System.out.print(i);
1521: System.out.print('\t');
1522: switch (getChunkIndex(fNodeType, chunk, index)) {
1523: case DocumentImpl.ELEMENT_DEFINITION_NODE: {
1524: System.out.print("EDef");
1525: break;
1526: }
1527: case Node.DOCUMENT_NODE: {
1528: System.out.print("Doc");
1529: break;
1530: }
1531: case Node.DOCUMENT_TYPE_NODE: {
1532: System.out.print("DType");
1533: break;
1534: }
1535: case Node.COMMENT_NODE: {
1536: System.out.print("Com");
1537: break;
1538: }
1539: case Node.PROCESSING_INSTRUCTION_NODE: {
1540: System.out.print("PI");
1541: break;
1542: }
1543: case Node.ELEMENT_NODE: {
1544: System.out.print("Elem");
1545: break;
1546: }
1547: case Node.ENTITY_NODE: {
1548: System.out.print("Ent");
1549: break;
1550: }
1551: case Node.ENTITY_REFERENCE_NODE: {
1552: System.out.print("ERef");
1553: break;
1554: }
1555: case Node.TEXT_NODE: {
1556: System.out.print("Text");
1557: break;
1558: }
1559: case Node.ATTRIBUTE_NODE: {
1560: System.out.print("Attr");
1561: break;
1562: }
1563: case DeferredNode.TYPE_NODE: {
1564: System.out.print("TypeInfo");
1565: break;
1566: }
1567: default: {
1568: System.out.print("?"
1569: + getChunkIndex(fNodeType, chunk, index));
1570: }
1571: }
1572: System.out.print('\t');
1573: System.out
1574: .print(getChunkValue(fNodeName, chunk, index));
1575: System.out.print('\t');
1576: System.out.print(getNodeValue(chunk, index));
1577: System.out.print('\t');
1578: System.out.print(getChunkValue(fNodeURI, chunk, index));
1579: System.out.print('\t');
1580: System.out.print(getChunkIndex(fNodeParent, chunk,
1581: index));
1582: System.out.print('\t');
1583: System.out.print(getChunkIndex(fNodeLastChild, chunk,
1584: index));
1585: System.out.print('\t');
1586: System.out.print(getChunkIndex(fNodePrevSib, chunk,
1587: index));
1588: System.out.print('\t');
1589: System.out
1590: .print(getChunkIndex(fNodeExtra, chunk, index));
1591: System.out.println();
1592: }
1593: System.out.println("# end table");
1594: }
1595:
1596: } // print()
1597:
1598: //
1599: // DeferredNode methods
1600: //
1601:
1602: /** Returns the node index. */
1603: public int getNodeIndex() {
1604: return 0;
1605: }
1606:
1607: //
1608: // Protected methods
1609: //
1610:
1611: /** Synchronizes the node's data. */
1612: protected void synchronizeData() {
1613:
1614: // no need to sync in the future
1615: needsSyncData(false);
1616:
1617: // fluff up enough nodes to fill identifiers hash
1618: if (fIdElement != null) {
1619:
1620: // REVISIT: There has to be a more efficient way of
1621: // doing this. But keep in mind that the
1622: // tree can have been altered and re-ordered
1623: // before all of the element nodes with ID
1624: // attributes have been registered. For now
1625: // this is reasonable and safe. -Ac
1626:
1627: IntVector path = new IntVector();
1628: for (int i = 0; i < fIdCount; i++) {
1629:
1630: // ignore if it's already been registered
1631: int elementNodeIndex = fIdElement[i];
1632: String idName = fIdName[i];
1633: if (idName == null) {
1634: continue;
1635: }
1636:
1637: // find path from this element to the root
1638: path.removeAllElements();
1639: int index = elementNodeIndex;
1640: do {
1641: path.addElement(index);
1642: int pchunk = index >> CHUNK_SHIFT;
1643: int pindex = index & CHUNK_MASK;
1644: index = getChunkIndex(fNodeParent, pchunk, pindex);
1645: } while (index != -1);
1646:
1647: // Traverse path (backwards), fluffing the elements
1648: // along the way. When this loop finishes, "place"
1649: // will contain the reference to the element node
1650: // we're interested in. -Ac
1651: Node place = this ;
1652: for (int j = path.size() - 2; j >= 0; j--) {
1653: index = path.elementAt(j);
1654: Node child = place.getLastChild();
1655: while (child != null) {
1656: if (child instanceof DeferredNode) {
1657: int nodeIndex = ((DeferredNode) child)
1658: .getNodeIndex();
1659: if (nodeIndex == index) {
1660: place = child;
1661: break;
1662: }
1663: }
1664: child = child.getPreviousSibling();
1665: }
1666: }
1667:
1668: // register the element
1669: Element element = (Element) place;
1670: putIdentifier0(idName, element);
1671: fIdName[i] = null;
1672:
1673: // see if there are more IDs on this element
1674: while (i + 1 < fIdCount
1675: && fIdElement[i + 1] == elementNodeIndex) {
1676: idName = fIdName[++i];
1677: if (idName == null) {
1678: continue;
1679: }
1680: putIdentifier0(idName, element);
1681: }
1682: }
1683:
1684: } // if identifiers
1685:
1686: } // synchronizeData()
1687:
1688: /**
1689: * Synchronizes the node's children with the internal structure.
1690: * Fluffing the children at once solves a lot of work to keep
1691: * the two structures in sync. The problem gets worse when
1692: * editing the tree -- this makes it a lot easier.
1693: */
1694: protected void synchronizeChildren() {
1695:
1696: if (needsSyncData()) {
1697: synchronizeData();
1698: /*
1699: * when we have elements with IDs this method is being recursively
1700: * called from synchronizeData, in which case we've already gone
1701: * through the following and we can now simply stop here.
1702: */
1703: if (!needsSyncChildren()) {
1704: return;
1705: }
1706: }
1707:
1708: // we don't want to generate any event for this so turn them off
1709: boolean orig = mutationEvents;
1710: mutationEvents = false;
1711:
1712: // no need to sync in the future
1713: needsSyncChildren(false);
1714:
1715: getNodeType(0);
1716:
1717: // create children and link them as siblings
1718: ChildNode first = null;
1719: ChildNode last = null;
1720: for (int index = getLastChild(0); index != -1; index = getPrevSibling(index)) {
1721:
1722: ChildNode node = (ChildNode) getNodeObject(index);
1723: if (last == null) {
1724: last = node;
1725: } else {
1726: first.previousSibling = node;
1727: }
1728: node.ownerNode = this ;
1729: node.isOwned(true);
1730: node.nextSibling = first;
1731: first = node;
1732:
1733: // save doctype and document type
1734: int type = node.getNodeType();
1735: if (type == Node.ELEMENT_NODE) {
1736: docElement = (ElementImpl) node;
1737: } else if (type == Node.DOCUMENT_TYPE_NODE) {
1738: docType = (DocumentTypeImpl) node;
1739: }
1740: }
1741:
1742: if (first != null) {
1743: firstChild = first;
1744: first.isFirstChild(true);
1745: lastChild(last);
1746: }
1747:
1748: // set mutation events flag back to its original value
1749: mutationEvents = orig;
1750:
1751: } // synchronizeChildren()
1752:
1753: /**
1754: * Synchronizes the node's children with the internal structure.
1755: * Fluffing the children at once solves a lot of work to keep
1756: * the two structures in sync. The problem gets worse when
1757: * editing the tree -- this makes it a lot easier.
1758: * This is not directly used in this class but this method is
1759: * here so that it can be shared by all deferred subclasses of AttrImpl.
1760: */
1761: protected final void synchronizeChildren(AttrImpl a, int nodeIndex) {
1762:
1763: // we don't want to generate any event for this so turn them off
1764: boolean orig = getMutationEvents();
1765: setMutationEvents(false);
1766:
1767: // no need to sync in the future
1768: a.needsSyncChildren(false);
1769:
1770: // create children and link them as siblings or simply store the value
1771: // as a String if all we have is one piece of text
1772: int last = getLastChild(nodeIndex);
1773: int prev = getPrevSibling(last);
1774: if (prev == -1) {
1775: a.value = getNodeValueString(nodeIndex);
1776: a.hasStringValue(true);
1777: } else {
1778: ChildNode firstNode = null;
1779: ChildNode lastNode = null;
1780: for (int index = last; index != -1; index = getPrevSibling(index)) {
1781:
1782: ChildNode node = (ChildNode) getNodeObject(index);
1783: if (lastNode == null) {
1784: lastNode = node;
1785: } else {
1786: firstNode.previousSibling = node;
1787: }
1788: node.ownerNode = a;
1789: node.isOwned(true);
1790: node.nextSibling = firstNode;
1791: firstNode = node;
1792: }
1793: if (lastNode != null) {
1794: a.value = firstNode; // firstChild = firstNode
1795: firstNode.isFirstChild(true);
1796: a.lastChild(lastNode);
1797: }
1798: a.hasStringValue(false);
1799: }
1800:
1801: // set mutation events flag back to its original value
1802: setMutationEvents(orig);
1803:
1804: } // synchronizeChildren(AttrImpl,int):void
1805:
1806: /**
1807: * Synchronizes the node's children with the internal structure.
1808: * Fluffing the children at once solves a lot of work to keep
1809: * the two structures in sync. The problem gets worse when
1810: * editing the tree -- this makes it a lot easier.
1811: * This is not directly used in this class but this method is
1812: * here so that it can be shared by all deferred subclasses of ParentNode.
1813: */
1814: protected final void synchronizeChildren(ParentNode p, int nodeIndex) {
1815:
1816: // we don't want to generate any event for this so turn them off
1817: boolean orig = getMutationEvents();
1818: setMutationEvents(false);
1819:
1820: // no need to sync in the future
1821: p.needsSyncChildren(false);
1822:
1823: // create children and link them as siblings
1824: ChildNode firstNode = null;
1825: ChildNode lastNode = null;
1826: for (int index = getLastChild(nodeIndex); index != -1; index = getPrevSibling(index)) {
1827:
1828: ChildNode node = (ChildNode) getNodeObject(index);
1829: if (lastNode == null) {
1830: lastNode = node;
1831: } else {
1832: firstNode.previousSibling = node;
1833: }
1834: node.ownerNode = p;
1835: node.isOwned(true);
1836: node.nextSibling = firstNode;
1837: firstNode = node;
1838: }
1839: if (lastNode != null) {
1840: p.firstChild = firstNode;
1841: firstNode.isFirstChild(true);
1842: p.lastChild(lastNode);
1843: }
1844:
1845: // set mutation events flag back to its original value
1846: setMutationEvents(orig);
1847:
1848: } // synchronizeChildren(ParentNode,int):void
1849:
1850: // utility methods
1851:
1852: /** Ensures that the internal tables are large enough. */
1853: protected void ensureCapacity(int chunk) {
1854: if (fNodeType == null) {
1855: // create buffers
1856: fNodeType = new int[INITIAL_CHUNK_COUNT][];
1857: fNodeName = new Object[INITIAL_CHUNK_COUNT][];
1858: fNodeValue = new Object[INITIAL_CHUNK_COUNT][];
1859: fNodeParent = new int[INITIAL_CHUNK_COUNT][];
1860: fNodeLastChild = new int[INITIAL_CHUNK_COUNT][];
1861: fNodePrevSib = new int[INITIAL_CHUNK_COUNT][];
1862: fNodeURI = new Object[INITIAL_CHUNK_COUNT][];
1863: fNodeExtra = new int[INITIAL_CHUNK_COUNT][];
1864: } else if (fNodeType.length <= chunk) {
1865: // resize the tables
1866: int newsize = chunk * 2;
1867:
1868: int[][] newArray = new int[newsize][];
1869: System.arraycopy(fNodeType, 0, newArray, 0, chunk);
1870: fNodeType = newArray;
1871:
1872: Object[][] newStrArray = new Object[newsize][];
1873: System.arraycopy(fNodeName, 0, newStrArray, 0, chunk);
1874: fNodeName = newStrArray;
1875:
1876: newStrArray = new Object[newsize][];
1877: System.arraycopy(fNodeValue, 0, newStrArray, 0, chunk);
1878: fNodeValue = newStrArray;
1879:
1880: newArray = new int[newsize][];
1881: System.arraycopy(fNodeParent, 0, newArray, 0, chunk);
1882: fNodeParent = newArray;
1883:
1884: newArray = new int[newsize][];
1885: System.arraycopy(fNodeLastChild, 0, newArray, 0, chunk);
1886: fNodeLastChild = newArray;
1887:
1888: newArray = new int[newsize][];
1889: System.arraycopy(fNodePrevSib, 0, newArray, 0, chunk);
1890: fNodePrevSib = newArray;
1891:
1892: newStrArray = new Object[newsize][];
1893: System.arraycopy(fNodeURI, 0, newStrArray, 0, chunk);
1894: fNodeURI = newStrArray;
1895:
1896: newArray = new int[newsize][];
1897: System.arraycopy(fNodeExtra, 0, newArray, 0, chunk);
1898: fNodeExtra = newArray;
1899: } else if (fNodeType[chunk] != null) {
1900: // Done - there's sufficient capacity
1901: return;
1902: }
1903:
1904: // create new chunks
1905: createChunk(fNodeType, chunk);
1906: createChunk(fNodeName, chunk);
1907: createChunk(fNodeValue, chunk);
1908: createChunk(fNodeParent, chunk);
1909: createChunk(fNodeLastChild, chunk);
1910: createChunk(fNodePrevSib, chunk);
1911: createChunk(fNodeURI, chunk);
1912: createChunk(fNodeExtra, chunk);
1913:
1914: // Done
1915: return;
1916:
1917: } // ensureCapacity(int,int)
1918:
1919: /** Creates a node of the specified type. */
1920: protected int createNode(short nodeType) {
1921: // ensure tables are large enough
1922: int chunk = fNodeCount >> CHUNK_SHIFT;
1923: int index = fNodeCount & CHUNK_MASK;
1924: ensureCapacity(chunk);
1925:
1926: // initialize node
1927: setChunkIndex(fNodeType, nodeType, chunk, index);
1928:
1929: // return node index number
1930: return fNodeCount++;
1931:
1932: } // createNode(short):int
1933:
1934: /**
1935: * Performs a binary search for a target value in an array of
1936: * values. The array of values must be in ascending sorted order
1937: * before calling this method and all array values must be
1938: * non-negative.
1939: *
1940: * @param values The array of values to search.
1941: * @param start The starting offset of the search.
1942: * @param end The ending offset of the search.
1943: * @param target The target value.
1944: *
1945: * @return This function will return the <i>first</i> occurrence
1946: * of the target value, or -1 if the target value cannot
1947: * be found.
1948: */
1949: protected static int binarySearch(final int values[], int start,
1950: int end, int target) {
1951:
1952: if (DEBUG_IDS) {
1953: System.out.println("binarySearch(), target: " + target);
1954: }
1955:
1956: // look for target value
1957: while (start <= end) {
1958:
1959: // is this the one we're looking for?
1960: int middle = (start + end) / 2;
1961: int value = values[middle];
1962: if (DEBUG_IDS) {
1963: System.out.print(" value: " + value + ", target: "
1964: + target + " // ");
1965: print(values, start, end, middle, target);
1966: }
1967: if (value == target) {
1968: while (middle > 0 && values[middle - 1] == target) {
1969: middle--;
1970: }
1971: if (DEBUG_IDS) {
1972: System.out.println("FOUND AT " + middle);
1973: }
1974: return middle;
1975: }
1976:
1977: // is this point higher or lower?
1978: if (value > target) {
1979: end = middle - 1;
1980: } else {
1981: start = middle + 1;
1982: }
1983:
1984: } // while
1985:
1986: // not found
1987: if (DEBUG_IDS) {
1988: System.out.println("NOT FOUND!");
1989: }
1990: return -1;
1991:
1992: } // binarySearch(int[],int,int,int):int
1993:
1994: //
1995: // Private methods
1996: //
1997: private static final int[] INIT_ARRAY = new int[CHUNK_SIZE + 1];
1998: static {
1999: for (int i = 0; i < CHUNK_SIZE; i++) {
2000: INIT_ARRAY[i] = -1;
2001: }
2002: }
2003:
2004: /** Creates the specified chunk in the given array of chunks. */
2005: private final void createChunk(int data[][], int chunk) {
2006: data[chunk] = new int[CHUNK_SIZE + 1];
2007: System.arraycopy(INIT_ARRAY, 0, data[chunk], 0, CHUNK_SIZE);
2008: }
2009:
2010: static final class RefCount {
2011: int fCount;
2012: }
2013:
2014: private final void createChunk(Object data[][], int chunk) {
2015: data[chunk] = new Object[CHUNK_SIZE + 1];
2016: data[chunk][CHUNK_SIZE] = new RefCount();
2017: }
2018:
2019: /**
2020: * Sets the specified value in the given of data at the chunk and index.
2021: *
2022: * @return Returns the old value.
2023: */
2024: private final int setChunkIndex(int data[][], int value, int chunk,
2025: int index) {
2026: if (value == -1) {
2027: return clearChunkIndex(data, chunk, index);
2028: }
2029: int[] dataChunk = data[chunk];
2030: // Re-create chunk if it was deleted.
2031: if (dataChunk == null) {
2032: createChunk(data, chunk);
2033: dataChunk = data[chunk];
2034: }
2035: int ovalue = dataChunk[index];
2036: if (ovalue == -1) {
2037: dataChunk[CHUNK_SIZE]++;
2038: }
2039: dataChunk[index] = value;
2040: return ovalue;
2041: }
2042:
2043: private final String setChunkValue(Object data[][], Object value,
2044: int chunk, int index) {
2045: if (value == null) {
2046: return clearChunkValue(data, chunk, index);
2047: }
2048: Object[] dataChunk = data[chunk];
2049: // Re-create chunk if it was deleted.
2050: if (dataChunk == null) {
2051: createChunk(data, chunk);
2052: dataChunk = data[chunk];
2053: }
2054: String ovalue = (String) dataChunk[index];
2055: if (ovalue == null) {
2056: RefCount c = (RefCount) dataChunk[CHUNK_SIZE];
2057: c.fCount++;
2058: }
2059: dataChunk[index] = value;
2060: return ovalue;
2061: }
2062:
2063: /**
2064: * Returns the specified value in the given data at the chunk and index.
2065: */
2066: private final int getChunkIndex(int data[][], int chunk, int index) {
2067: return data[chunk] != null ? data[chunk][index] : -1;
2068: }
2069:
2070: private final String getChunkValue(Object data[][], int chunk,
2071: int index) {
2072: return data[chunk] != null ? (String) data[chunk][index] : null;
2073: }
2074:
2075: private final String getNodeValue(int chunk, int index) {
2076: Object data = fNodeValue[chunk][index];
2077: if (data == null) {
2078: return null;
2079: } else if (data instanceof String) {
2080: return (String) data;
2081: } else {
2082: // type information
2083: return data.toString();
2084: }
2085: }
2086:
2087: /**
2088: * Clears the specified value in the given data at the chunk and index.
2089: * Note that this method will clear the given chunk if the reference
2090: * count becomes zero.
2091: *
2092: * @return Returns the old value.
2093: */
2094: private final int clearChunkIndex(int data[][], int chunk, int index) {
2095: int value = data[chunk] != null ? data[chunk][index] : -1;
2096: if (value != -1) {
2097: data[chunk][CHUNK_SIZE]--;
2098: data[chunk][index] = -1;
2099: if (data[chunk][CHUNK_SIZE] == 0) {
2100: data[chunk] = null;
2101: }
2102: }
2103: return value;
2104: }
2105:
2106: private final String clearChunkValue(Object data[][], int chunk,
2107: int index) {
2108: String value = data[chunk] != null ? (String) data[chunk][index]
2109: : null;
2110: if (value != null) {
2111: data[chunk][index] = null;
2112: RefCount c = (RefCount) data[chunk][CHUNK_SIZE];
2113: c.fCount--;
2114: if (c.fCount == 0) {
2115: data[chunk] = null;
2116: }
2117: }
2118: return value;
2119: }
2120:
2121: /**
2122: * This version of putIdentifier is needed to avoid fluffing
2123: * all of the paths to ID attributes when a node object is
2124: * created that contains an ID attribute.
2125: */
2126: private final void putIdentifier0(String idName, Element element) {
2127:
2128: if (DEBUG_IDS) {
2129: System.out.println("putIdentifier0(" + idName + ", "
2130: + element + ')');
2131: }
2132:
2133: // create hashtable
2134: if (identifiers == null) {
2135: identifiers = new java.util.Hashtable();
2136: }
2137:
2138: // save ID and its associated element
2139: identifiers.put(idName, element);
2140:
2141: } // putIdentifier0(String,Element)
2142:
2143: /** Prints the ID array. */
2144: private static void print(int values[], int start, int end,
2145: int middle, int target) {
2146:
2147: if (DEBUG_IDS) {
2148: System.out.print(start);
2149: System.out.print(" [");
2150: for (int i = start; i < end; i++) {
2151: if (middle == i) {
2152: System.out.print("!");
2153: }
2154: System.out.print(values[i]);
2155: if (values[i] == target) {
2156: System.out.print("*");
2157: }
2158: if (i < end - 1) {
2159: System.out.print(" ");
2160: }
2161: }
2162: System.out.println("] " + end);
2163: }
2164:
2165: } // print(int[],int,int,int,int)
2166:
2167: //
2168: // Classes
2169: //
2170:
2171: /**
2172: * A simple integer vector.
2173: */
2174: static final class IntVector {
2175:
2176: //
2177: // Data
2178: //
2179:
2180: /** Data. */
2181: private int data[];
2182:
2183: /** Size. */
2184: private int size;
2185:
2186: //
2187: // Public methods
2188: //
2189:
2190: /** Returns the length of this vector. */
2191: public int size() {
2192: return size;
2193: }
2194:
2195: /** Returns the element at the specified index. */
2196: public int elementAt(int index) {
2197: return data[index];
2198: }
2199:
2200: /** Appends an element to the end of the vector. */
2201: public void addElement(int element) {
2202: ensureCapacity(size + 1);
2203: data[size++] = element;
2204: }
2205:
2206: /** Clears the vector. */
2207: public void removeAllElements() {
2208: size = 0;
2209: }
2210:
2211: //
2212: // Private methods
2213: //
2214:
2215: /** Makes sure that there is enough storage. */
2216: private void ensureCapacity(int newsize) {
2217:
2218: if (data == null) {
2219: data = new int[newsize + 15];
2220: } else if (newsize > data.length) {
2221: int newdata[] = new int[newsize + 15];
2222: System.arraycopy(data, 0, newdata, 0, data.length);
2223: data = newdata;
2224: }
2225:
2226: } // ensureCapacity(int)
2227:
2228: } // class IntVector
2229:
2230: } // class DeferredDocumentImpl
|