KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > apache > xerces > dom > DeferredDocumentImpl


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 1999-2001 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 1999, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58 package org.enhydra.apache.xerces.dom;
59
60 import java.util.Vector JavaDoc;
61
62 import org.enhydra.apache.xerces.framework.XMLAttrList;
63 import org.enhydra.apache.xerces.utils.StringPool;
64 import org.w3c.dom.Element JavaDoc;
65 import org.w3c.dom.Node JavaDoc;
66
67 /**
68  * The Document interface represents the entire HTML or XML document.
69  * Conceptually, it is the root of the document tree, and provides the
70  * primary access to the document's data.
71  * <P>
72  * Since elements, text nodes, comments, processing instructions,
73  * etc. cannot exist outside the context of a Document, the Document
74  * interface also contains the factory methods needed to create these
75  * objects. The Node objects created have a ownerDocument attribute
76  * which associates them with the Document within whose context they
77  * were created.
78  *
79  * @version
80  * @since PR-DOM-Level-1-19980818.
81  */

82 public class DeferredDocumentImpl
83     extends DocumentImpl
84     implements DeferredNode {
85
86     //
87
// Constants
88
//
89

90     /** Serialization version. */
91     static final long serialVersionUID = 5186323580749626857L;
92
93     // debugging
94

95     /** To include code for printing the ref count tables. */
96     private static final boolean DEBUG_PRINT_REF_COUNTS = false;
97
98     /** To include code for printing the internal tables. */
99     private static final boolean DEBUG_PRINT_TABLES = false;
100
101     /** To debug identifiers set to true and recompile. */
102     private static final boolean DEBUG_IDS = false;
103
104     // protected
105

106     /** Chunk shift. */
107     protected static final int CHUNK_SHIFT = 11; // 2^11 = 2k
108

109     /** Chunk size. */
110     protected static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
111
112     /** Chunk mask. */
113     protected static final int CHUNK_MASK = CHUNK_SIZE - 1;
114
115     /** Initial chunk size. */
116     protected static final int INITIAL_CHUNK_COUNT = (1 << (16 - CHUNK_SHIFT)); // 2^16 = 64k
117

118     //
119
// Data
120
//
121

122     // lazy-eval information
123

124     /** Node count. */
125     protected transient int fNodeCount = 0;
126
127     /** Node types. */
128     protected transient int fNodeType[][];
129
130     /** Node names. */
131     protected transient int fNodeName[][];
132
133     /** Node values. */
134     protected transient int fNodeValue[][];
135
136     /** Node parents. */
137     protected transient int fNodeParent[][];
138
139     /** Node first children. */
140     protected transient int fNodeLastChild[][];
141
142     /** Node prev siblings. */
143     protected transient int fNodePrevSib[][];
144
145     /** Node namespace URI. */
146     protected transient int fNodeURI[][];
147
148     /** Identifier count. */
149     protected transient int fIdCount;
150
151     /** Identifier name indexes. */
152     protected transient int fIdName[];
153
154     /** Identifier element indexes. */
155     protected transient int fIdElement[];
156
157     /** String pool cache. */
158     protected transient StringPool fStringPool;
159
160     /** DOM2: For namespace support in the deferred case.
161      */

162     // Implementation Note: The deferred element and attribute must know how to
163
// interpret the int representing the qname.
164
protected boolean fNamespacesEnabled = false;
165
166     private final StringBuffer JavaDoc fBufferStr = new StringBuffer JavaDoc();
167     private final Vector JavaDoc fStrChunks = new Vector JavaDoc();
168     //
169
// Constructors
170
//
171

172     /**
173      * NON-DOM: Actually creating a Document is outside the DOM's spec,
174      * since it has to operate in terms of a particular implementation.
175      */

176     public DeferredDocumentImpl(StringPool stringPool) {
177         this(stringPool, false);
178     } // <init>(ParserState)
179

180     /**
181      * NON-DOM: Actually creating a Document is outside the DOM's spec,
182      * since it has to operate in terms of a particular implementation.
183      */

184     public DeferredDocumentImpl(StringPool stringPool, boolean namespacesEnabled) {
185         this(stringPool, namespacesEnabled, false);
186     } // <init>(ParserState,boolean)
187

188     /** Experimental constructor. */
189     public DeferredDocumentImpl(StringPool stringPool,
190                                 boolean namespaces, boolean grammarAccess) {
191         super(grammarAccess);
192
193         fStringPool = stringPool;
194
195         needsSyncData(true);
196         needsSyncChildren(true);
197
198         fNamespacesEnabled = namespaces;
199
200     } // <init>(StringPool,boolean,boolean)
201

202     //
203
// Public methods
204
//
205

206     /** Returns the cached parser.getNamespaces() value.*/
207     boolean getNamespacesEnabled() {
208         return fNamespacesEnabled;
209     }
210
211     // internal factory methods
212

213     /** Creates a document node in the table. */
214     public int createDocument() {
215         int nodeIndex = createNode(Node.DOCUMENT_NODE);
216         return nodeIndex;
217     }
218
219     /** Creates a doctype. */
220     public int createDocumentType(int rootElementNameIndex, int publicId, int systemId) {
221
222         // create node
223
int nodeIndex = createNode(Node.DOCUMENT_TYPE_NODE);
224         int chunk = nodeIndex >> CHUNK_SHIFT;
225         int index = nodeIndex & CHUNK_MASK;
226
227         // added for DOM2: createDoctype factory method includes
228
// name, publicID, systemID
229

230         // create extra data node
231
int extraDataIndex = createNode((short)0); // node type unimportant
232
int echunk = extraDataIndex >> CHUNK_SHIFT;
233         int eindex = extraDataIndex & CHUNK_MASK;
234
235         // save name, public id, system id
236
setChunkIndex(fNodeName, rootElementNameIndex, chunk, index);
237         setChunkIndex(fNodeValue, extraDataIndex, chunk, index);
238         setChunkIndex(fNodeName, publicId, echunk, eindex);
239         setChunkIndex(fNodeValue, systemId, echunk, eindex);
240
241         // return node index
242
return nodeIndex;
243
244     } // createDocumentType(int,int,int):int
245

246     public void setInternalSubset(int doctypeIndex, int subsetIndex) {
247         int chunk = doctypeIndex >> CHUNK_SHIFT;
248         int index = doctypeIndex & CHUNK_MASK;
249         int extraDataIndex = fNodeValue[chunk][index];
250         int echunk = extraDataIndex >> CHUNK_SHIFT;
251         int eindex = extraDataIndex & CHUNK_MASK;
252         setChunkIndex(fNodeLastChild, subsetIndex, echunk, eindex);
253     }
254
255     /** Creates a notation in the table. */
256     public int createNotation(int notationName, int publicId, int systemId) throws Exception JavaDoc {
257
258         // create node
259
int nodeIndex = createNode(Node.NOTATION_NODE);
260         int chunk = nodeIndex >> CHUNK_SHIFT;
261         int index = nodeIndex & CHUNK_MASK;
262
263         // create extra data node
264
int extraDataIndex = createNode((short)0); // node type unimportant
265
int echunk = extraDataIndex >> CHUNK_SHIFT;
266         int eindex = extraDataIndex & CHUNK_MASK;
267
268         // save name, public id, system id, and notation name
269
setChunkIndex(fNodeName, notationName, chunk, index);
270         setChunkIndex(fNodeValue, extraDataIndex, chunk, index);
271         setChunkIndex(fNodeName, publicId, echunk, eindex);
272         setChunkIndex(fNodeValue, systemId, echunk, eindex);
273
274         // return node index
275
return nodeIndex;
276
277     } // createNotation(int,int,int):int
278

279     /** Creates an entity in the table. */
280     public int createEntity(int entityName, int publicId, int systemId, int notationName) throws Exception JavaDoc {
281         // create node
282
int nodeIndex = createNode(Node.ENTITY_NODE);
283         int chunk = nodeIndex >> CHUNK_SHIFT;
284         int index = nodeIndex & CHUNK_MASK;
285
286         // create extra data node
287
int extraDataIndex = createNode((short)0); // node type unimportant
288
int echunk = extraDataIndex >> CHUNK_SHIFT;
289         int eindex = extraDataIndex & CHUNK_MASK;
290
291         // create extra data node DOM Level 3 - el
292
int extraDataIndex2 = createNode((short)0); // node type unimportant
293
int echunk2 = extraDataIndex2 >> CHUNK_SHIFT;
294         int eindex2 = extraDataIndex2 & CHUNK_MASK;
295
296         // save name, public id, system id, and notation name
297
setChunkIndex(fNodeName, entityName, chunk, index);
298         setChunkIndex(fNodeValue, extraDataIndex, chunk, index);
299         setChunkIndex(fNodeLastChild, notationName, echunk, eindex);
300         setChunkIndex(fNodeName, publicId, echunk, eindex);
301         setChunkIndex(fNodeValue, extraDataIndex2, echunk, eindex);
302         setChunkIndex(fNodeName, systemId, echunk2, eindex2);
303
304         // initialize encoding and verison for DOM Level 3 - el
305
setChunkIndex(fNodeValue, -1, echunk2, eindex2);
306         setChunkIndex(fNodeLastChild, -1, echunk2, eindex2);
307
308         // return node index
309
return nodeIndex;
310
311     } // createEntity(int,int,int,int):int
312

313     // DOM Level 3 - el
314
// setting encoding and version
315
public void setEntityInfo(int currentEntityDecl, int versionIndex, int encodingIndex){
316         int eNodeIndex = getNodeValue(getNodeValue(currentEntityDecl, false), false);
317         if (eNodeIndex !=-1) {
318             int echunk = eNodeIndex >> CHUNK_SHIFT;
319             int eindex = eNodeIndex & CHUNK_MASK;
320             setChunkIndex(fNodeValue, versionIndex, echunk, eindex);
321             setChunkIndex(fNodeLastChild, encodingIndex, echunk, eindex);
322         }
323     }
324
325     /** Creates an entity reference node in the table. */
326     public int createEntityReference(int nameIndex) throws Exception JavaDoc {
327
328         // create node
329
int nodeIndex = createNode(Node.ENTITY_REFERENCE_NODE);
330         int chunk = nodeIndex >> CHUNK_SHIFT;
331         int index = nodeIndex & CHUNK_MASK;
332         setChunkIndex(fNodeName, nameIndex, chunk, index);
333
334         // return node index
335
return nodeIndex;
336
337     } // createEntityReference(int):int
338

339     /** Creates an element node in the table. */
340     public int createElement(int elementNameIndex,
341                              XMLAttrList attrList, int attrListIndex) {
342         return createElement(elementNameIndex, -1, attrList, attrListIndex);
343     }
344
345     /** Creates an element node with a URI in the table. */
346     public int createElement(int elementNameIndex, int elementURIIndex,
347                              XMLAttrList attrList, int attrListIndex) {
348
349         // create node
350
int elementNodeIndex = createNode(Node.ELEMENT_NODE);
351         int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
352         int elementIndex = elementNodeIndex & CHUNK_MASK;
353         setChunkIndex(fNodeName, elementNameIndex, elementChunk, elementIndex);
354         setChunkIndex(fNodeURI, elementURIIndex, elementChunk, elementIndex);
355
356         // create attributes
357
if (attrListIndex != -1) {
358             int first = attrList.getFirstAttr(attrListIndex);
359             int lastAttrNodeIndex = -1;
360             int lastAttrChunk = -1;
361             int lastAttrIndex = -1;
362             for (int index = first;
363                  index != -1;
364                  index = attrList.getNextAttr(index)) {
365
366                 // create attribute
367
int attrNodeIndex =
368                     createAttribute(attrList.getAttrName(index),
369                                     attrList.getAttrURI(index),
370                                     attrList.getAttValue(index),
371                                     attrList.isSpecified(index));
372                 int attrChunk = attrNodeIndex >> CHUNK_SHIFT;
373                 int attrIndex = attrNodeIndex & CHUNK_MASK;
374                 setChunkIndex(fNodeParent, elementNodeIndex, attrChunk, attrIndex);
375
376                 // add links
377
if (index == first) {
378                     setChunkIndex(fNodeValue, attrNodeIndex, elementChunk, elementIndex);
379                 }
380                 else {
381                     setChunkIndex(fNodePrevSib, attrNodeIndex, lastAttrChunk, lastAttrIndex);
382                 }
383
384                 // save last chunk and index
385
lastAttrNodeIndex = attrNodeIndex;
386                 lastAttrChunk = attrChunk;
387                 lastAttrIndex = attrIndex;
388             }
389         }
390
391         // return node index
392
return elementNodeIndex;
393
394     } // createElement(int,XMLAttrList,int):int
395
/** Creates an attribute in the table. */
396     public int createAttribute(int attrNameIndex,
397                                int attrValueIndex, boolean specified) {
398         return createAttribute(attrNameIndex, -1, attrValueIndex, specified);
399     }
400
401     /** Creates an attribute with a URI in the table. */
402     public int createAttribute(int attrNameIndex, int attrURIIndex,
403                                int attrValueIndex, boolean specified) {
404
405         // create node
406
int nodeIndex = createNode(NodeImpl.ATTRIBUTE_NODE);
407         int chunk = nodeIndex >> CHUNK_SHIFT;
408         int index = nodeIndex & CHUNK_MASK;
409         setChunkIndex(fNodeName, attrNameIndex, chunk, index);
410         setChunkIndex(fNodeURI, attrURIIndex, chunk, index);
411         setChunkIndex(fNodeValue, specified ? 1 : 0, chunk, index);
412
413         // append value as text node
414
int textNodeIndex = createTextNode(attrValueIndex, false);
415         appendChild(nodeIndex, textNodeIndex);
416
417         // return node index
418
return nodeIndex;
419
420     } // createAttribute(int,int,boolean):int
421

422     /** Creates an element definition in the table. */
423     public int createElementDefinition(int elementNameIndex) {
424
425         // create node
426
int nodeIndex = createNode(NodeImpl.ELEMENT_DEFINITION_NODE);
427         int chunk = nodeIndex >> CHUNK_SHIFT;
428         int index = nodeIndex & CHUNK_MASK;
429         setChunkIndex(fNodeName, elementNameIndex, chunk, index);
430
431         // return node index
432
return nodeIndex;
433
434     } // createElementDefinition(int):int
435

436     /** Creates a text node in the table. */
437     public int createTextNode(int dataIndex, boolean ignorableWhitespace) {
438
439         // create node
440
int nodeIndex = createNode(Node.TEXT_NODE);
441         int chunk = nodeIndex >> CHUNK_SHIFT;
442         int index = nodeIndex & CHUNK_MASK;
443         setChunkIndex(fNodeValue, dataIndex, chunk, index);
444         // use last child to store ignorableWhitespace info
445
setChunkIndex(fNodeLastChild,
446                       ignorableWhitespace ? 1 : 0, chunk, index);
447
448         // return node index
449
return nodeIndex;
450
451     } // createTextNode(int,boolean):int
452

453     /** Creates a CDATA section node in the table. */
454     public int createCDATASection(int dataIndex, boolean ignorableWhitespace) {
455
456         // create node
457
int nodeIndex = createNode(Node.CDATA_SECTION_NODE);
458         int chunk = nodeIndex >> CHUNK_SHIFT;
459         int index = nodeIndex & CHUNK_MASK;
460         setChunkIndex(fNodeValue, dataIndex, chunk, index);
461         // use last child to store ignorableWhitespace info
462
setChunkIndex(fNodeLastChild,
463                       ignorableWhitespace ? 1 : 0, chunk, index);
464
465         // return node index
466
return nodeIndex;
467
468     } // createCDATASection(int,boolean):int
469

470     /** Creates a processing instruction node in the table. */
471     public int createProcessingInstruction(int targetIndex, int dataIndex) {
472
473         // create node
474
int nodeIndex = createNode(Node.PROCESSING_INSTRUCTION_NODE);
475         int chunk = nodeIndex >> CHUNK_SHIFT;
476         int index = nodeIndex & CHUNK_MASK;
477         setChunkIndex(fNodeName, targetIndex, chunk, index);
478         setChunkIndex(fNodeValue, dataIndex, chunk, index);
479
480         // return node index
481
return nodeIndex;
482
483     } // createProcessingInstruction(int,int):int
484

485     /** Creates a comment node in the table. */
486     public int createComment(int dataIndex) {
487
488         // create node
489
int nodeIndex = createNode(Node.COMMENT_NODE);
490         int chunk = nodeIndex >> CHUNK_SHIFT;
491         int index = nodeIndex & CHUNK_MASK;
492         setChunkIndex(fNodeValue, dataIndex, chunk, index);
493
494         // return node index
495
return nodeIndex;
496
497     } // createComment(int):int
498

499     /** Appends a child to the specified parent in the table. */
500     public void appendChild(int parentIndex, int childIndex) {
501
502         // append parent index
503
int pchunk = parentIndex >> CHUNK_SHIFT;
504         int pindex = parentIndex & CHUNK_MASK;
505         int cchunk = childIndex >> CHUNK_SHIFT;
506         int cindex = childIndex & CHUNK_MASK;
507         setChunkIndex(fNodeParent, parentIndex, cchunk, cindex);
508
509         // set previous sibling of new child
510
int olast = getChunkIndex(fNodeLastChild, pchunk, pindex);
511         setChunkIndex(fNodePrevSib, olast, cchunk, cindex);
512
513         // update parent's last child
514
setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex);
515
516
517     } // appendChild(int,int)
518

519     /** Adds an attribute node to the specified element. */
520     public int setAttributeNode(int elemIndex, int attrIndex) {
521
522         int echunk = elemIndex >> CHUNK_SHIFT;
523         int eindex = elemIndex & CHUNK_MASK;
524         int achunk = attrIndex >> CHUNK_SHIFT;
525         int aindex = attrIndex & CHUNK_MASK;
526
527         // see if this attribute is already here
528
String JavaDoc attrName =
529             fStringPool.toString(getChunkIndex(fNodeName, achunk, aindex));
530         int oldAttrIndex = getChunkIndex(fNodeValue, echunk, eindex);
531         int nextIndex = -1;
532         int oachunk = -1;
533         int oaindex = -1;
534         while (oldAttrIndex != -1) {
535             oachunk = oldAttrIndex >> CHUNK_SHIFT;
536             oaindex = oldAttrIndex & CHUNK_MASK;
537             String JavaDoc oldAttrName =
538               fStringPool.toString(getChunkIndex(fNodeName, oachunk, oaindex));
539             if (oldAttrName.equals(attrName)) {
540                 break;
541             }
542             nextIndex = oldAttrIndex;
543             oldAttrIndex = getChunkIndex(fNodePrevSib, oachunk, oaindex);
544         }
545
546         // remove old attribute
547
if (oldAttrIndex != -1) {
548
549             // patch links
550
int prevIndex = getChunkIndex(fNodePrevSib, oachunk, oaindex);
551             if (nextIndex == -1) {
552                 setChunkIndex(fNodeValue, prevIndex, echunk, eindex);
553             }
554             else {
555                 int pchunk = nextIndex >> CHUNK_SHIFT;
556                 int pindex = nextIndex & CHUNK_MASK;
557                 setChunkIndex(fNodePrevSib, prevIndex, pchunk, pindex);
558             }
559
560             // remove connections to siblings
561
clearChunkIndex(fNodeType, oachunk, oaindex);
562             clearChunkIndex(fNodeName, oachunk, oaindex);
563             clearChunkIndex(fNodeValue, oachunk, oaindex);
564             clearChunkIndex(fNodeParent, oachunk, oaindex);
565             clearChunkIndex(fNodePrevSib, oachunk, oaindex);
566             int attrTextIndex =
567                 clearChunkIndex(fNodeLastChild, oachunk, oaindex);
568             int atchunk = attrTextIndex >> CHUNK_SHIFT;
569             int atindex = attrTextIndex & CHUNK_MASK;
570             clearChunkIndex(fNodeType, atchunk, atindex);
571             clearChunkIndex(fNodeValue, atchunk, atindex);
572             clearChunkIndex(fNodeParent, atchunk, atindex);
573             clearChunkIndex(fNodeLastChild, atchunk, atindex);
574         }
575
576         // add new attribute
577
int prevIndex = getChunkIndex(fNodeValue, echunk, eindex);
578         setChunkIndex(fNodeValue, attrIndex, echunk, eindex);
579         setChunkIndex(fNodePrevSib, prevIndex, achunk, aindex);
580
581         // return
582
return oldAttrIndex;
583
584     } // setAttributeNode(int,int):int
585

586     /** Inserts a child before the specified node in the table. */
587     public int insertBefore(int parentIndex, int newChildIndex, int refChildIndex) {
588
589         if (refChildIndex == -1) {
590             appendChild(parentIndex, newChildIndex);
591             return newChildIndex;
592         }
593
594         int nchunk = newChildIndex >> CHUNK_SHIFT;
595         int nindex = newChildIndex & CHUNK_MASK;
596         int rchunk = refChildIndex >> CHUNK_SHIFT;
597         int rindex = refChildIndex & CHUNK_MASK;
598         int previousIndex = getChunkIndex(fNodePrevSib, rchunk, rindex);
599         setChunkIndex(fNodePrevSib, newChildIndex, rchunk, rindex);
600         setChunkIndex(fNodePrevSib, previousIndex, nchunk, nindex);
601
602         return newChildIndex;
603
604     } // insertBefore(int,int,int):int
605

606     /** Sets the last child of the parentIndex to childIndex. */
607     public void setAsLastChild(int parentIndex, int childIndex) {
608
609         int pchunk = parentIndex >> CHUNK_SHIFT;
610         int pindex = parentIndex & CHUNK_MASK;
611         int chunk = childIndex >> CHUNK_SHIFT;
612         int index = childIndex & CHUNK_MASK;
613         setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex);
614     } // setAsLastChild(int,int)
615

616     /**
617      * Returns the parent node of the given node.
618      * <em>Calling this method does not free the parent index.</em>
619      */

620     public int getParentNode(int nodeIndex) {
621         return getParentNode(nodeIndex, false);
622     }
623
624     /**
625      * Returns the parent node of the given node.
626      * @param free True to free parent node.
627      */

628     public int getParentNode(int nodeIndex, boolean free) {
629
630         if (nodeIndex == -1) {
631             return -1;
632         }
633
634         int chunk = nodeIndex >> CHUNK_SHIFT;
635         int index = nodeIndex & CHUNK_MASK;
636         return free ? clearChunkIndex(fNodeParent, chunk, index)
637                     : getChunkIndex(fNodeParent, chunk, index);
638
639     } // getParentNode(int):int
640

641     /** Returns the last child of the given node. */
642     public int getLastChild(int nodeIndex) {
643         return getLastChild(nodeIndex, true);
644     }
645
646     /**
647      * Returns the last child of the given node.
648      * @param free True to free child index.
649      */

650     public int getLastChild(int nodeIndex, boolean free) {
651
652         if (nodeIndex == -1) {
653             return -1;
654         }
655
656         int chunk = nodeIndex >> CHUNK_SHIFT;
657         int index = nodeIndex & CHUNK_MASK;
658         return free ? clearChunkIndex(fNodeLastChild, chunk, index)
659                     : getChunkIndex(fNodeLastChild, chunk, index);
660
661     } // getLastChild(int,boolean):int
662

663     /**
664      * Returns the prev sibling of the given node.
665      * This is post-normalization of Text Nodes.
666      */

667     public int getPrevSibling(int nodeIndex) {
668         return getPrevSibling(nodeIndex, true);
669     }
670
671     /**
672      * Returns the prev sibling of the given node.
673      * @param free True to free sibling index.
674      */

675     public int getPrevSibling(int nodeIndex, boolean free) {
676
677         if (nodeIndex == -1) {
678             return -1;
679         }
680
681         int chunk = nodeIndex >> CHUNK_SHIFT;
682         int index = nodeIndex & CHUNK_MASK;
683         int type = getChunkIndex(fNodeType, chunk, index);
684         if (type == Node.TEXT_NODE) {
685             do {
686                 nodeIndex = getChunkIndex(fNodePrevSib, chunk, index);
687                 if (nodeIndex == -1) {
688                     break;
689                 }
690                 chunk = nodeIndex >> CHUNK_SHIFT;
691                 index = nodeIndex & CHUNK_MASK;
692                 type = getChunkIndex(fNodeType, chunk, index);
693             } while (type == Node.TEXT_NODE);
694         }
695         else {
696             nodeIndex = getChunkIndex(fNodePrevSib, chunk, index);
697         }
698
699         return nodeIndex;
700
701     } // getPrevSibling(int,boolean):int
702

703     /**
704      * Returns the <i>real</i> prev sibling of the given node,
705      * directly from the data structures. Used by TextImpl#getNodeValue()
706      * to normalize values.
707      */

708     public int getRealPrevSibling(int nodeIndex) {
709         return getRealPrevSibling(nodeIndex, true);
710     }
711
712     /**
713      * Returns the <i>real</i> prev sibling of the given node.
714      * @param free True to free sibling index.
715      */

716     public int getRealPrevSibling(int nodeIndex, boolean free) {
717
718         if (nodeIndex == -1) {
719             return -1;
720         }
721
722         int chunk = nodeIndex >> CHUNK_SHIFT;
723         int index = nodeIndex & CHUNK_MASK;
724         return free ? clearChunkIndex(fNodePrevSib, chunk, index)
725                     : getChunkIndex(fNodePrevSib, chunk, index);
726
727     } // getReadPrevSibling(int,boolean):int
728

729     /**
730      * Returns the index of the element definition in the table
731      * with the specified name index, or -1 if no such definition
732      * exists.
733      */

734     public int lookupElementDefinition(int elementNameIndex) {
735
736         if (fNodeCount > 1) {
737
738             // find doctype
739
int docTypeIndex = -1;
740             int nchunk = 0;
741             int nindex = 0;
742             for (int index = getChunkIndex(fNodeLastChild, nchunk, nindex);
743                  index != -1;
744                  index = getChunkIndex(fNodePrevSib, nchunk, nindex)) {
745
746                 nchunk = index >> CHUNK_SHIFT;
747                 nindex = index & CHUNK_MASK;
748                 if (getChunkIndex(fNodeType, nchunk, nindex) == Node.DOCUMENT_TYPE_NODE) {
749                     docTypeIndex = index;
750                     break;
751                 }
752             }
753
754             // find element definition
755
if (docTypeIndex == -1) {
756                 return -1;
757             }
758             nchunk = docTypeIndex >> CHUNK_SHIFT;
759             nindex = docTypeIndex & CHUNK_MASK;
760             for (int index = getChunkIndex(fNodeLastChild, nchunk, nindex);
761                  index != -1;
762                  index = getChunkIndex(fNodePrevSib, nchunk, nindex)) {
763
764                 nchunk = index >> CHUNK_SHIFT;
765                 nindex = index & CHUNK_MASK;
766                 if (getChunkIndex(fNodeName, nchunk, nindex) == elementNameIndex) {
767                     return index;
768                 }
769             }
770         }
771
772         return -1;
773
774     } // lookupElementDefinition(int):int
775

776     /** Instantiates the requested node object. */
777     public DeferredNode getNodeObject(int nodeIndex) {
778
779         // is there anything to do?
780
if (nodeIndex == -1) {
781             return null;
782         }
783
784         // get node type
785
int chunk = nodeIndex >> CHUNK_SHIFT;
786         int index = nodeIndex & CHUNK_MASK;
787         int type = getChunkIndex(fNodeType, chunk, index);
788         if (type != Node.TEXT_NODE) {
789             clearChunkIndex(fNodeType, chunk, index);
790         }
791
792         // create new node
793
DeferredNode node = null;
794         switch (type) {
795
796             //
797
// Standard DOM node types
798
//
799

800             case Node.ATTRIBUTE_NODE: {
801         if (fNamespacesEnabled) {
802             node = new DeferredAttrNSImpl(this, nodeIndex);
803         } else {
804             node = new DeferredAttrImpl(this, nodeIndex);
805         }
806                 break;
807             }
808
809             case Node.CDATA_SECTION_NODE: {
810                 node = new DeferredCDATASectionImpl(this, nodeIndex);
811                 break;
812             }
813
814             case Node.COMMENT_NODE: {
815                 node = new DeferredCommentImpl(this, nodeIndex);
816                 break;
817             }
818
819             // NOTE: Document fragments can never be "fast".
820
//
821
// The parser will never ask to create a document
822
// fragment during the parse. Document fragments
823
// are used by the application *after* the parse.
824
//
825
// case Node.DOCUMENT_FRAGMENT_NODE: { break; }
826
case Node.DOCUMENT_NODE: {
827                 // this node is never "fast"
828
node = this;
829                 break;
830             }
831
832             case Node.DOCUMENT_TYPE_NODE: {
833                 node = new DeferredDocumentTypeImpl(this, nodeIndex);
834                 // save the doctype node
835
docType = (DocumentTypeImpl)node;
836                 break;
837             }
838
839             case Node.ELEMENT_NODE: {
840
841                 if (DEBUG_IDS) {
842                     System.out.println("getNodeObject(ELEMENT_NODE): "+nodeIndex);
843                 }
844
845                 // create node
846
if (fNamespacesEnabled) {
847             node = new DeferredElementNSImpl(this, nodeIndex);
848         } else {
849             node = new DeferredElementImpl(this, nodeIndex);
850         }
851
852                 // save the document element node
853
if (docElement == null) {
854                     docElement = (ElementImpl)node;
855                 }
856
857                 // check to see if this element needs to be
858
// registered for its ID attributes
859
if (fIdElement != null) {
860                     int idIndex = DeferredDocumentImpl.binarySearch(fIdElement, 0, fIdCount-1, nodeIndex);
861                     while (idIndex != -1) {
862
863                         if (DEBUG_IDS) {
864                             System.out.println(" id index: "+idIndex);
865                             System.out.println(" fIdName["+idIndex+
866                                                "]: "+fIdName[idIndex]);
867                         }
868
869                         // register ID
870
int nameIndex = fIdName[idIndex];
871                         if (nameIndex != -1) {
872                             String JavaDoc name = fStringPool.toString(nameIndex);
873                             if (DEBUG_IDS) {
874                                 System.out.println(" name: "+name);
875                                 System.out.print("getNodeObject()#");
876                             }
877                             putIdentifier0(name, (Element JavaDoc)node);
878                             fIdName[idIndex] = -1;
879                         }
880
881                         // continue if there are more IDs for
882
// this element
883
if (idIndex + 1 < fIdCount &&
884                             fIdElement[idIndex + 1] == nodeIndex) {
885                             idIndex++;
886                         }
887                         else {
888                             idIndex = -1;
889                         }
890                     }
891                 }
892                 break;
893             }
894
895             case Node.ENTITY_NODE: {
896                 node = new DeferredEntityImpl(this, nodeIndex);
897                 break;
898             }
899
900             case Node.ENTITY_REFERENCE_NODE: {
901                 node = new DeferredEntityReferenceImpl(this, nodeIndex);
902                 break;
903             }
904
905             case Node.NOTATION_NODE: {
906                 node = new DeferredNotationImpl(this, nodeIndex);
907                 break;
908             }
909
910             case Node.PROCESSING_INSTRUCTION_NODE: {
911                 node = new DeferredProcessingInstructionImpl(this, nodeIndex);
912                 break;
913             }
914
915             case Node.TEXT_NODE: {
916                 node = new DeferredTextImpl(this, nodeIndex);
917                 break;
918             }
919
920             //
921
// non-standard DOM node types
922
//
923

924             case NodeImpl.ELEMENT_DEFINITION_NODE: {
925                 node = new DeferredElementDefinitionImpl(this, nodeIndex);
926                 break;
927             }
928
929             default: {
930                 throw new IllegalArgumentException JavaDoc("type: "+type);
931             }
932
933         } // switch node type
934

935         // store and return
936
if (node != null) {
937             return node;
938         }
939
940         // error
941
throw new IllegalArgumentException JavaDoc();
942
943     } // createNodeObject(int):Node
944

945     /** Returns the name of the given node. */
946     public String JavaDoc getNodeNameString(int nodeIndex) {
947         return getNodeNameString(nodeIndex, true);
948     } // getNodeNameString(int):String
949

950     /**
951      * Returns the name of the given node.
952      * @param free True to free the string index.
953      */

954     public String JavaDoc getNodeNameString(int nodeIndex, boolean free) {
955
956         if (nodeIndex == -1) {
957             return null;
958         }
959
960         int chunk = nodeIndex >> CHUNK_SHIFT;
961         int index = nodeIndex & CHUNK_MASK;
962         int nameIndex = free
963                       ? clearChunkIndex(fNodeName, chunk, index)
964                       : getChunkIndex(fNodeName, chunk, index);
965         if (nameIndex == -1) {
966             return null;
967         }
968
969         return fStringPool.toString(nameIndex);
970
971     } // getNodeNameString(int,boolean):String
972

973     /** Returns the value of the given node. */
974     public String JavaDoc getNodeValueString(int nodeIndex) {
975         return getNodeValueString(nodeIndex, true);
976     } // getNodeValueString(int):String
977

978     /**
979      * Returns the value of the given node.
980      * @param free True to free the string index.
981      */

982     public String JavaDoc getNodeValueString(int nodeIndex, boolean free) {
983
984         if (nodeIndex == -1) {
985             return null;
986         }
987
988         int chunk = nodeIndex >> CHUNK_SHIFT;
989         int index = nodeIndex & CHUNK_MASK;
990         int valueIndex = free
991                        ? clearChunkIndex(fNodeValue, chunk, index)
992                        : getChunkIndex(fNodeValue, chunk, index);
993         if (valueIndex == -1) {
994             return null;
995         }
996
997         int type = getChunkIndex(fNodeType, chunk, index);
998         if (type == Node.TEXT_NODE) {
999             int prevSib = getRealPrevSibling(nodeIndex);
1000            if (prevSib != -1 && getNodeType(prevSib, false) == Node.TEXT_NODE) {
1001                fStrChunks.addElement(fStringPool.toString(valueIndex));
1002                do {
1003                    chunk = prevSib >> CHUNK_SHIFT;
1004                    index = prevSib & CHUNK_MASK;
1005                    valueIndex = getChunkIndex(fNodeValue, chunk, index);
1006                    // NOTE: This has to be done backwards because the
1007
// children are placed backwards.
1008
fStrChunks.addElement(fStringPool.toString(valueIndex));
1009                    prevSib = getChunkIndex(fNodePrevSib, chunk, index);
1010                    if (prevSib == -1) {
1011                        break;
1012                    }
1013                } while (getNodeType(prevSib, false) == Node.TEXT_NODE);
1014                for (int i=fStrChunks.size()-1; i>=0; i--) {
1015                    fBufferStr.append((String JavaDoc)fStrChunks.elementAt(i));
1016                }
1017                                                        
1018                String JavaDoc value = fBufferStr.toString();
1019                fStrChunks.setSize(0);
1020                fBufferStr.setLength(0);
1021                return value;
1022            }
1023        }
1024
1025        return fStringPool.toString(valueIndex);
1026
1027    } // getNodeValueString(int,boolean):String
1028

1029    /** Returns the real int name of the given node. */
1030    public int getNodeName(int nodeIndex) {
1031        return getNodeName(nodeIndex, true);
1032    }
1033
1034    /**
1035     * Returns the real int name of the given node.
1036     * @param free True to free the name index.
1037     */

1038    public int getNodeName(int nodeIndex, boolean free) {
1039
1040        if (nodeIndex == -1) {
1041            return -1;
1042        }
1043
1044        int chunk = nodeIndex >> CHUNK_SHIFT;
1045        int index = nodeIndex & CHUNK_MASK;
1046        return free ? clearChunkIndex(fNodeName, chunk, index)
1047                    : getChunkIndex(fNodeName, chunk, index);
1048
1049    } // getNodeName(int,boolean):int
1050

1051    /**
1052     * Returns the real int value of the given node.
1053     * Used by AttrImpl to store specified value (1 == true).
1054     */

1055    public int getNodeValue(int nodeIndex) {
1056        return getNodeValue(nodeIndex, true);
1057    }
1058
1059    /**
1060     * Returns the real int value of the given node.
1061     * @param free True to free the value index.
1062     */

1063    public int getNodeValue(int nodeIndex, boolean free) {
1064
1065        if (nodeIndex == -1) {
1066            return -1;
1067        }
1068
1069        int chunk = nodeIndex >> CHUNK_SHIFT;
1070        int index = nodeIndex & CHUNK_MASK;
1071        return free ? clearChunkIndex(fNodeValue, chunk, index)
1072                    : getChunkIndex(fNodeValue, chunk, index);
1073
1074    } // getNodeValue(int,boolean):int
1075

1076    /** Returns the type of the given node. */
1077    public short getNodeType(int nodeIndex) {
1078        return getNodeType(nodeIndex, true);
1079    }
1080
1081    /**
1082     * Returns the type of the given node.
1083     * @param True to free type index.
1084     */

1085    public short getNodeType(int nodeIndex, boolean free) {
1086
1087        if (nodeIndex == -1) {
1088            return -1;
1089        }
1090
1091        int chunk = nodeIndex >> CHUNK_SHIFT;
1092        int index = nodeIndex & CHUNK_MASK;
1093        if (free) {
1094            return (short)clearChunkIndex(fNodeType, chunk, index);
1095        }
1096        return (short)getChunkIndex(fNodeType, chunk, index);
1097
1098    } // getNodeType(int):int
1099

1100    /** Returns the attribute value of the given name. */
1101    public int getAttribute(int elemIndex, int nameIndex) {
1102        if (elemIndex == -1 || nameIndex == -1) {
1103            return -1;
1104        }
1105        int echunk = elemIndex >> CHUNK_SHIFT;
1106        int eindex = elemIndex & CHUNK_MASK;
1107        int attrIndex = getChunkIndex(fNodeValue, echunk, eindex);
1108        while (attrIndex != -1) {
1109            int achunk = attrIndex >> CHUNK_SHIFT;
1110            int aindex = attrIndex & CHUNK_MASK;
1111            if (getChunkIndex(fNodeName, achunk, aindex) == nameIndex) {
1112                return getChunkIndex(fNodeValue, achunk, aindex);
1113            }
1114            attrIndex = getChunkIndex(fNodePrevSib, achunk, aindex);
1115        }
1116        return -1;
1117    }
1118
1119    /** Returns the URI of the given node. */
1120    public short getNodeURI(int nodeIndex) {
1121        return getNodeURI(nodeIndex, true);
1122    }
1123
1124    /**
1125     * Returns the URI of the given node.
1126     * @param True to free URI index.
1127     */

1128    public short getNodeURI(int nodeIndex, boolean free) {
1129
1130        if (nodeIndex == -1) {
1131            return -1;
1132        }
1133
1134        int chunk = nodeIndex >> CHUNK_SHIFT;
1135        int index = nodeIndex & CHUNK_MASK;
1136        if (free) {
1137            return (short)clearChunkIndex(fNodeURI, chunk, index);
1138        }
1139        return (short)getChunkIndex(fNodeURI, chunk, index);
1140
1141    } // getNodeURI(int):int
1142

1143    // identifier maintenance
1144

1145    /** Registers an identifier name with a specified element node. */
1146    public void putIdentifier(int nameIndex, int elementNodeIndex) {
1147
1148        if (DEBUG_IDS) {
1149            System.out.println("putIdentifier("+nameIndex+", "+elementNodeIndex+')'+
1150                               " // "+
1151                               fStringPool.toString(nameIndex)+
1152                               ", "+
1153                               fStringPool.toString(getChunkIndex(fNodeName, elementNodeIndex >> CHUNK_SHIFT, elementNodeIndex & CHUNK_MASK)));
1154        }
1155
1156        // initialize arrays
1157
if (fIdName == null) {
1158            fIdName = new int[64];
1159            fIdElement = new int[64];
1160        }
1161
1162        // resize arrays
1163
if (fIdCount == fIdName.length) {
1164            int idName[] = new int[fIdCount * 2];
1165            System.arraycopy(fIdName, 0, idName, 0, fIdCount);
1166            fIdName = idName;
1167
1168            int idElement[] = new int[idName.length];
1169            System.arraycopy(fIdElement, 0, idElement, 0, fIdCount);
1170            fIdElement = idElement;
1171        }
1172
1173        // store identifier
1174
fIdName[fIdCount] = nameIndex;
1175        fIdElement[fIdCount] = elementNodeIndex;
1176        fIdCount++;
1177
1178    } // putIdentifier(int,int)
1179

1180    //
1181
// DEBUG
1182
//
1183

1184    /** Prints out the tables. */
1185    public void print() {
1186
1187        if (DEBUG_PRINT_REF_COUNTS) {
1188            System.out.print("num\t");
1189            System.out.print("type\t");
1190            System.out.print("name\t");
1191            System.out.print("val\t");
1192            System.out.print("par\t");
1193            System.out.print("fch\t");
1194            System.out.print("nsib");
1195            System.out.println();
1196            for (int i = 0; i < fNodeType.length; i++) {
1197                if (fNodeType[i] != null) {
1198                    // separator
1199
System.out.print("--------");
1200                    System.out.print("--------");
1201                    System.out.print("--------");
1202                    System.out.print("--------");
1203                    System.out.print("--------");
1204                    System.out.print("--------");
1205                    System.out.print("--------");
1206                    System.out.println();
1207
1208                    // set count
1209
System.out.print(i);
1210                    System.out.print('\t');
1211                    System.out.print(fNodeType[i][CHUNK_SIZE]);
1212                    System.out.print('\t');
1213                    System.out.print(fNodeName[i][CHUNK_SIZE]);
1214                    System.out.print('\t');
1215                    System.out.print(fNodeValue[i][CHUNK_SIZE]);
1216                    System.out.print('\t');
1217                    System.out.print(fNodeParent[i][CHUNK_SIZE]);
1218                    System.out.print('\t');
1219                    System.out.print(fNodeLastChild[i][CHUNK_SIZE]);
1220                    System.out.print('\t');
1221                    System.out.print(fNodePrevSib[i][CHUNK_SIZE]);
1222                    System.out.println();
1223
1224                    // clear count
1225
System.out.print(i);
1226                    System.out.print('\t');
1227                    System.out.print(fNodeType[i][CHUNK_SIZE + 1]);
1228                    System.out.print('\t');
1229                    System.out.print(fNodeName[i][CHUNK_SIZE + 1]);
1230                    System.out.print('\t');
1231                    System.out.print(fNodeValue[i][CHUNK_SIZE + 1]);
1232                    System.out.print('\t');
1233                    System.out.print(fNodeParent[i][CHUNK_SIZE + 1]);
1234                    System.out.print('\t');
1235                    System.out.print(fNodeLastChild[i][CHUNK_SIZE + 1]);
1236                    System.out.print('\t');
1237                    System.out.print(fNodePrevSib[i][CHUNK_SIZE + 1]);
1238                    System.out.println();
1239                }
1240            }
1241        }
1242
1243        if (DEBUG_PRINT_TABLES) {
1244            // This assumes that the document is small
1245
System.out.println("# start table");
1246            for (int i = 0; i < fNodeCount; i++) {
1247                int chunk = i >> CHUNK_SHIFT;
1248                int index = i & CHUNK_MASK;
1249                if (i % 10 == 0) {
1250                    System.out.print("num\t");
1251                    System.out.print("type\t");
1252                    System.out.print("name\t");
1253                    System.out.print("val\t");
1254                    System.out.print("par\t");
1255                    System.out.print("fch\t");
1256                    System.out.print("nsib");
1257                    System.out.println();
1258                }
1259                System.out.print(i);
1260                System.out.print('\t');
1261                System.out.print(getChunkIndex(fNodeType, chunk, index));
1262                System.out.print('\t');
1263                System.out.print(getChunkIndex(fNodeName, chunk, index));
1264                System.out.print('\t');
1265                System.out.print(getChunkIndex(fNodeValue, chunk, index));
1266                System.out.print('\t');
1267                System.out.print(getChunkIndex(fNodeParent, chunk, index));
1268                System.out.print('\t');
1269                System.out.print(getChunkIndex(fNodeLastChild, chunk, index));
1270                System.out.print('\t');
1271                System.out.print(getChunkIndex(fNodePrevSib, chunk, index));
1272                /***
1273                System.out.print(fNodeType[0][i]);
1274                System.out.print('\t');
1275                System.out.print(fNodeName[0][i]);
1276                System.out.print('\t');
1277                System.out.print(fNodeValue[0][i]);
1278                System.out.print('\t');
1279                System.out.print(fNodeParent[0][i]);
1280                System.out.print('\t');
1281                System.out.print(fNodeFirstChild[0][i]);
1282                System.out.print('\t');
1283                System.out.print(fNodeLastChild[0][i]);
1284                System.out.print('\t');
1285                System.out.print(fNodePrevSib[0][i]);
1286                System.out.print('\t');
1287                System.out.print(fNodeNextSib[0][i]);
1288                /***/

1289                System.out.println();
1290            }
1291            System.out.println("# end table");
1292        }
1293
1294    } // print()
1295

1296    //
1297
// DeferredNode methods
1298
//
1299

1300    /** Returns the node index. */
1301    public int getNodeIndex() {
1302        return 0;
1303    }
1304
1305    //
1306
// Protected methods
1307
//
1308

1309    /** access to string pool. */
1310    protected StringPool getStringPool() {
1311        return fStringPool;
1312    }
1313
1314    /** Synchronizes the node's data. */
1315    protected void synchronizeData() {
1316
1317        // no need to sync in the future
1318
needsSyncData(false);
1319
1320        // fluff up enough nodes to fill identifiers hash
1321
if (fIdElement != null) {
1322
1323            // REVISIT: There has to be a more efficient way of
1324
// doing this. But keep in mind that the
1325
// tree can have been altered and re-ordered
1326
// before all of the element nodes with ID
1327
// attributes have been registered. For now
1328
// this is reasonable and safe. -Ac
1329

1330            IntVector path = new IntVector();
1331            for (int i = 0; i < fIdCount; i++) {
1332
1333                // ignore if it's already been registered
1334
int elementNodeIndex = fIdElement[i];
1335                int idNameIndex = fIdName[i];
1336                if (idNameIndex == -1) {
1337                    continue;
1338                }
1339
1340                // find path from this element to the root
1341
path.removeAllElements();
1342                int index = elementNodeIndex;
1343                do {
1344                    path.addElement(index);
1345                    int pchunk = index >> CHUNK_SHIFT;
1346                    int pindex = index & CHUNK_MASK;
1347                    index = getChunkIndex(fNodeParent, pchunk, pindex);
1348                } while (index != -1);
1349
1350                // Traverse path (backwards), fluffing the elements
1351
// along the way. When this loop finishes, "place"
1352
// will contain the reference to the element node
1353
// we're interested in. -Ac
1354
Node JavaDoc place = this;
1355                for (int j = path.size() - 2; j >= 0; j--) {
1356                    index = path.elementAt(j);
1357                    Node JavaDoc child = place.getLastChild();
1358                    while (child != null) {
1359                        if (child instanceof DeferredNode) {
1360                            int nodeIndex = ((DeferredNode)child).getNodeIndex();
1361                            if (nodeIndex == index) {
1362                                place = child;
1363                                break;
1364                            }
1365                        }
1366                        child = child.getPreviousSibling();
1367                    }
1368                }
1369
1370                // register the element
1371
Element JavaDoc element = (Element JavaDoc)place;
1372                String JavaDoc name = fStringPool.toString(idNameIndex);
1373                putIdentifier0(name, element);
1374                fIdName[i] = -1;
1375
1376                // see if there are more IDs on this element
1377
while (i + 1 < fIdCount && fIdElement[i + 1] == elementNodeIndex) {
1378                    idNameIndex = fIdName[++i];
1379                    if (idNameIndex == -1) {
1380                        continue;
1381                    }
1382                    name = fStringPool.toString(idNameIndex);
1383                    putIdentifier0(name, element);
1384                }
1385            }
1386
1387        } // if identifiers
1388

1389    } // synchronizeData()
1390

1391    /**
1392     * Synchronizes the node's children with the internal structure.
1393     * Fluffing the children at once solves a lot of work to keep
1394     * the two structures in sync. The problem gets worse when
1395     * editing the tree -- this makes it a lot easier.
1396     */

1397    protected void synchronizeChildren() {
1398
1399        if (needsSyncData()) {
1400            synchronizeData();
1401            /*
1402             * when we have elements with IDs this method is being recursively
1403             * called from synchronizeData, in which case we've already gone
1404             * through the following and we can now simply stop here.
1405             */

1406            if (!needsSyncChildren()) {
1407                return;
1408            }
1409        }
1410
1411        // we don't want to generate any event for this so turn them off
1412
boolean orig = mutationEvents;
1413        mutationEvents = false;
1414
1415        // no need to sync in the future
1416
needsSyncChildren(false);
1417
1418        getNodeType(0);
1419
1420        // create children and link them as siblings
1421
ChildNode first = null;
1422        ChildNode last = null;
1423        for (int index = getLastChild(0);
1424             index != -1;
1425             index = getPrevSibling(index)) {
1426
1427            ChildNode node = (ChildNode)getNodeObject(index);
1428            if (last == null) {
1429                last = node;
1430            }
1431            else {
1432                first.previousSibling = node;
1433            }
1434            node.ownerNode = this;
1435            node.isOwned(true);
1436            node.nextSibling = first;
1437            first = node;
1438
1439            // save doctype and document type
1440
int type = node.getNodeType();
1441            if (type == Node.ELEMENT_NODE) {
1442                docElement = (ElementImpl)node;
1443            }
1444            else if (type == Node.DOCUMENT_TYPE_NODE) {
1445                docType = (DocumentTypeImpl)node;
1446            }
1447        }
1448
1449        if (first != null) {
1450            firstChild = first;
1451            first.isFirstChild(true);
1452            lastChild(last);
1453        }
1454
1455        // set mutation events flag back to its original value
1456
mutationEvents = orig;
1457
1458    } // synchronizeChildren()
1459

1460    /**
1461     * Synchronizes the node's children with the internal structure.
1462     * Fluffing the children at once solves a lot of work to keep
1463     * the two structures in sync. The problem gets worse when
1464     * editing the tree -- this makes it a lot easier.
1465     * This is not directly used in this class but this method is
1466     * here so that it can be shared by all deferred subclasses of AttrImpl.
1467     */

1468    protected final void synchronizeChildren(AttrImpl a, int nodeIndex) {
1469
1470        // we don't want to generate any event for this so turn them off
1471
boolean orig = getMutationEvents();
1472        setMutationEvents(false);
1473
1474        // no need to sync in the future
1475
a.needsSyncChildren(false);
1476
1477        // create children and link them as siblings or simply store the value
1478
// as a String if all we have is one piece of text
1479
int last = getLastChild(nodeIndex);
1480        int prev = getPrevSibling(last);
1481        if (prev == -1) {
1482            a.value = getNodeValueString(last);
1483            a.hasStringValue(true);
1484        }
1485        else {
1486            ChildNode firstNode = null;
1487            ChildNode lastNode = null;
1488            for (int index = last; index != -1;
1489                 index = getPrevSibling(index)) {
1490
1491                ChildNode node = (ChildNode) getNodeObject(index);
1492                if (lastNode == null) {
1493                    lastNode = node;
1494                }
1495                else {
1496                    firstNode.previousSibling = node;
1497                }
1498                node.ownerNode = a;
1499                node.isOwned(true);
1500                node.nextSibling = firstNode;
1501                firstNode = node;
1502            }
1503            if (lastNode != null) {
1504                a.value = firstNode; // firstChild = firstNode
1505
firstNode.isFirstChild(true);
1506                a.lastChild(lastNode);
1507            }
1508            a.hasStringValue(false);
1509        }
1510
1511        // set mutation events flag back to its original value
1512
setMutationEvents(orig);
1513
1514    } // synchronizeChildren(AttrImpl,int):void
1515

1516
1517    /**
1518     * Synchronizes the node's children with the internal structure.
1519     * Fluffing the children at once solves a lot of work to keep
1520     * the two structures in sync. The problem gets worse when
1521     * editing the tree -- this makes it a lot easier.
1522     * This is not directly used in this class but this method is
1523     * here so that it can be shared by all deferred subclasses of ParentNode.
1524     */

1525    protected final void synchronizeChildren(ParentNode p, int nodeIndex) {
1526
1527        // we don't want to generate any event for this so turn them off
1528
boolean orig = getMutationEvents();
1529        setMutationEvents(false);
1530
1531        // no need to sync in the future
1532
p.needsSyncChildren(false);
1533
1534        // create children and link them as siblings
1535
ChildNode firstNode = null;
1536        ChildNode lastNode = null;
1537        for (int index = getLastChild(nodeIndex);
1538             index != -1;
1539             index = getPrevSibling(index)) {
1540
1541            ChildNode node = (ChildNode) getNodeObject(index);
1542            if (lastNode == null) {
1543                lastNode = node;
1544            }
1545            else {
1546                firstNode.previousSibling = node;
1547            }
1548            node.ownerNode = p;
1549            node.isOwned(true);
1550            node.nextSibling = firstNode;
1551            firstNode = node;
1552        }
1553        if (lastNode != null) {
1554            p.firstChild = firstNode;
1555            firstNode.isFirstChild(true);
1556            p.lastChild(lastNode);
1557        }
1558
1559        // set mutation events flag back to its original value
1560
setMutationEvents(orig);
1561
1562    } // synchronizeChildren(ParentNode,int):void
1563

1564    // utility methods
1565

1566    /** Ensures that the internal tables are large enough. */
1567    protected boolean ensureCapacity(int chunk, int index) {
1568
1569        // create buffers
1570
if (fNodeType == null) {
1571            fNodeType = new int[INITIAL_CHUNK_COUNT][];
1572            fNodeName = new int[INITIAL_CHUNK_COUNT][];
1573            fNodeValue = new int[INITIAL_CHUNK_COUNT][];
1574            fNodeParent = new int[INITIAL_CHUNK_COUNT][];
1575            fNodeLastChild = new int[INITIAL_CHUNK_COUNT][];
1576            fNodePrevSib = new int[INITIAL_CHUNK_COUNT][];
1577            fNodeURI = new int[INITIAL_CHUNK_COUNT][];
1578        }
1579
1580        // return true if table is already big enough
1581
try {
1582            return fNodeType[chunk][index] != 0;
1583        }
1584
1585        // resize the tables
1586
catch (ArrayIndexOutOfBoundsException JavaDoc ex) {
1587            int newsize = chunk * 2;
1588
1589            int[][] newArray = new int[newsize][];
1590            System.arraycopy(fNodeType, 0, newArray, 0, chunk);
1591            fNodeType = newArray;
1592
1593            newArray = new int[newsize][];
1594            System.arraycopy(fNodeName, 0, newArray, 0, chunk);
1595            fNodeName = newArray;
1596
1597            newArray = new int[newsize][];
1598            System.arraycopy(fNodeValue, 0, newArray, 0, chunk);
1599            fNodeValue = newArray;
1600
1601            newArray = new int[newsize][];
1602            System.arraycopy(fNodeParent, 0, newArray, 0, chunk);
1603            fNodeParent = newArray;
1604
1605            newArray = new int[newsize][];
1606            System.arraycopy(fNodeLastChild, 0, newArray, 0, chunk);
1607            fNodeLastChild = newArray;
1608
1609            newArray = new int[newsize][];
1610            System.arraycopy(fNodePrevSib, 0, newArray, 0, chunk);
1611            fNodePrevSib = newArray;
1612
1613            newArray = new int[newsize][];
1614            System.arraycopy(fNodeURI, 0, newArray, 0, chunk);
1615            fNodeURI = newArray;
1616        }
1617
1618        catch (NullPointerException JavaDoc ex) {
1619            // ignore
1620
}
1621
1622        // create chunks
1623
createChunk(fNodeType, chunk);
1624        createChunk(fNodeName, chunk);
1625        createChunk(fNodeValue, chunk);
1626        createChunk(fNodeParent, chunk);
1627        createChunk(fNodeLastChild, chunk);
1628        createChunk(fNodePrevSib, chunk);
1629        createChunk(fNodeURI, chunk);
1630
1631        // success
1632
return true;
1633
1634    } // ensureCapacity(int,int):boolean
1635

1636    /** Creates a node of the specified type. */
1637    protected int createNode(short nodeType) {
1638
1639        // ensure tables are large enough
1640
int chunk = fNodeCount >> CHUNK_SHIFT;
1641        int index = fNodeCount & CHUNK_MASK;
1642        ensureCapacity(chunk, index);
1643
1644        // initialize node
1645
setChunkIndex(fNodeType, nodeType, chunk, index);
1646
1647        // return node index number
1648
return fNodeCount++;
1649
1650    } // createNode(short):int
1651

1652    /**
1653     * Performs a binary search for a target value in an array of
1654     * values. The array of values must be in ascending sorted order
1655     * before calling this method and all array values must be
1656     * non-negative.
1657     *
1658     * @param values The array of values to search.
1659     * @param start The starting offset of the search.
1660     * @param end The ending offset of the search.
1661     * @param target The target value.
1662     *
1663     * @return This function will return the <i>first</i> occurrence
1664     * of the target value, or -1 if the target value cannot
1665     * be found.
1666     */

1667    protected static int binarySearch(final int values[],
1668                                      int start, int end, int target) {
1669
1670        if (DEBUG_IDS) {
1671            System.out.println("binarySearch(), target: "+target);
1672        }
1673
1674        // look for target value
1675
while (start <= end) {
1676
1677            // is this the one we're looking for?
1678
int middle = (start + end) / 2;
1679            int value = values[middle];
1680            if (DEBUG_IDS) {
1681                System.out.print(" value: "+value+", target: "+target+" // ");
1682                print(values, start, end, middle, target);
1683            }
1684            if (value == target) {
1685                while (middle > 0 && values[middle - 1] == target) {
1686                    middle--;
1687                }
1688                if (DEBUG_IDS) {
1689                    System.out.println("FOUND AT "+middle);
1690                }
1691                return middle;
1692            }
1693
1694            // is this point higher or lower?
1695
if (value > target) {
1696                end = middle - 1;
1697            }
1698            else {
1699                start = middle + 1;
1700            }
1701
1702        } // while
1703

1704        // not found
1705
if (DEBUG_IDS) {
1706            System.out.println("NOT FOUND!");
1707        }
1708        return -1;
1709
1710    } // binarySearch(int[],int,int,int):int
1711

1712    //
1713
// Private methods
1714
//
1715

1716    /** Creates the specified chunk in the given array of chunks. */
1717    private final void createChunk(int data[][], int chunk) {
1718        data[chunk] = new int[CHUNK_SIZE + 2];
1719        for (int i = 0; i < CHUNK_SIZE; i++) {
1720            data[chunk][i] = -1;
1721        }
1722    }
1723
1724    /**
1725     * Sets the specified value in the given of data at the chunk and index.
1726     *
1727     * @return Returns the old value.
1728     */

1729    private final int setChunkIndex(int data[][], int value, int chunk, int index) {
1730        if (value == -1) {
1731            return clearChunkIndex(data, chunk, index);
1732        }
1733        int ovalue = data[chunk][index];
1734        if (ovalue == -1) {
1735            data[chunk][CHUNK_SIZE]++;
1736        }
1737        data[chunk][index] = value;
1738        return ovalue;
1739    }
1740
1741    /**
1742     * Returns the specified value in the given data at the chunk and index.
1743     */

1744    private final int getChunkIndex(int data[][], int chunk, int index) {
1745        return data[chunk] != null ? data[chunk][index] : -1;
1746    }
1747
1748    /**
1749     * Clears the specified value in the given data at the chunk and index.
1750     * Note that this method will clear the given chunk if the reference
1751     * count becomes zero.
1752     *
1753     * @return Returns the old value.
1754     */

1755    private final int clearChunkIndex(int data[][], int chunk, int index) {
1756        int value = data[chunk] != null ? data[chunk][index] : -1;
1757        if (value != -1) {
1758            data[chunk][CHUNK_SIZE + 1]++;
1759            data[chunk][index] = -1;
1760            if (data[chunk][CHUNK_SIZE] == data[chunk][CHUNK_SIZE + 1]) {
1761                data[chunk] = null;
1762            }
1763        }
1764        return value;
1765    }
1766
1767    /**
1768     * This version of putIdentifier is needed to avoid fluffing
1769     * all of the paths to ID attributes when a node object is
1770     * created that contains an ID attribute.
1771     */

1772    private final void putIdentifier0(String JavaDoc idName, Element JavaDoc element) {
1773
1774        if (DEBUG_IDS) {
1775            System.out.println("putIdentifier0("+
1776                               idName+", "+
1777                               element+')');
1778        }
1779
1780        // create hashtable
1781
if (identifiers == null) {
1782            identifiers = new java.util.Hashtable JavaDoc();
1783        }
1784
1785        // save ID and its associated element
1786
identifiers.put(idName, element);
1787
1788    } // putIdentifier0(String,Element)
1789

1790    /** Prints the ID array. */
1791    private static void print(int values[], int start, int end,
1792                              int middle, int target) {
1793
1794        if (DEBUG_IDS) {
1795            System.out.print(start);
1796            System.out.print(" [");
1797            for (int i = start; i < end; i++) {
1798                if (middle == i) {
1799                    System.out.print("!");
1800                }
1801                System.out.print(values[i]);
1802                if (values[i] == target) {
1803                    System.out.print("*");
1804                }
1805                if (i < end - 1) {
1806                    System.out.print(" ");
1807                }
1808            }
1809            System.out.println("] "+end);
1810        }
1811
1812    } // print(int[],int,int,int,int)
1813

1814    //
1815
// Classes
1816
//
1817

1818    /**
1819     * A simple integer vector.
1820     */

1821    static class IntVector {
1822
1823        //
1824
// Data
1825
//
1826

1827        /** Data. */
1828        private int data[];
1829
1830        /** Size. */
1831        private int size;
1832
1833        //
1834
// Public methods
1835
//
1836

1837        /** Returns the length of this vector. */
1838        public int size() {
1839            return size;
1840        }
1841
1842        /** Returns the element at the specified index. */
1843        public int elementAt(int index) {
1844            return data[index];
1845        }
1846
1847        /** Appends an element to the end of the vector. */
1848        public void addElement(int element) {
1849            ensureCapacity(size + 1);
1850            data[size++] = element;
1851        }
1852
1853        /** Clears the vector. */
1854        public void removeAllElements() {
1855            size = 0;
1856        }
1857
1858        //
1859
// Private methods
1860
//
1861

1862        /** Makes sure that there is enough storage. */
1863        private void ensureCapacity(int newsize) {
1864
1865            if (data == null) {
1866                data = new int[newsize + 15];
1867            }
1868            else if (newsize > data.length) {
1869                int newdata[] = new int[newsize + 15];
1870                System.arraycopy(data, 0, newdata, 0, data.length);
1871                data = newdata;
1872            }
1873
1874        } // ensureCapacity(int)
1875

1876    } // class IntVector
1877

1878} // class DeferredDocumentImpl
1879
Popular Tags