2
* Licensed to the Apache Software Foundation (ASF) under one or more
3
* contributor license agreements. See the NOTICE file distributed with
4
* this work for additional information regarding copyright ownership.
5
* The ASF licenses this file to You under the Apache License, Version 2.0
6
* (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
18
package org.apache.xerces.dom;
20
import org.w3c.dom.DOMImplementation;
21
import org.w3c.dom.Element;
22
import org.w3c.dom.Node;
24
import java.util.Vector;
27
* The Document interface represents the entire HTML or XML document.
28
* Conceptually, it is the root of the document tree, and provides the
29
* primary access to the document's data.
31
* Since elements, text nodes, comments, processing instructions,
32
* etc. cannot exist outside the context of a Document, the Document
33
* interface also contains the factory methods needed to create these
34
* objects. The Node objects created have a ownerDocument attribute
35
* which associates them with the Document within whose context they
40
* @version $Id: DeferredDocumentImpl.java,v 1.2 2009/12/10 03:18:32 matthewoliver Exp $
41
* @since PR-DOM-Level-1-19980818.
43
public class DeferredDocumentImpl
45
implements DeferredNode {
51
/** Serialization version. */
52
static final long serialVersionUID = 5186323580749626857L;
56
/** To include code for printing the ref count tables. */
57
private static final boolean DEBUG_PRINT_REF_COUNTS = false;
59
/** To include code for printing the internal tables. */
60
private static final boolean DEBUG_PRINT_TABLES = false;
62
/** To debug identifiers set to true and recompile. */
63
private static final boolean DEBUG_IDS = false;
68
protected static final int CHUNK_SHIFT = 11; // 2^11 = 2k
71
protected static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
74
protected static final int CHUNK_MASK = CHUNK_SIZE - 1;
76
/** Initial chunk size. */
77
protected static final int INITIAL_CHUNK_COUNT = (1 << (16 - CHUNK_SHIFT)); // 2^16 = 64k
83
// lazy-eval information
84
// To maximize memory consumption the actual semantic of these fields vary
85
// depending on the node type.
88
protected transient int fNodeCount = 0;
91
protected transient int fNodeType[][];
94
protected transient Object fNodeName[][];
97
protected transient Object fNodeValue[][];
100
protected transient int fNodeParent[][];
102
/** Node first children. */
103
protected transient int fNodeLastChild[][];
105
/** Node prev siblings. */
106
protected transient int fNodePrevSib[][];
108
/** Node namespace URI. */
109
protected transient Object fNodeURI[][];
112
protected transient int fNodeExtra[][];
114
/** Identifier count. */
115
protected transient int fIdCount;
117
/** Identifier name indexes. */
118
protected transient String fIdName[];
120
/** Identifier element indexes. */
121
protected transient int fIdElement[];
123
/** DOM2: For namespace support in the deferred case.
125
// Implementation Note: The deferred element and attribute must know how to
126
// interpret the int representing the qname.
127
protected boolean fNamespacesEnabled = false;
132
private transient final StringBuffer fBufferStr = new StringBuffer();
133
private transient final Vector fStrChunks = new Vector();
140
* NON-DOM: Actually creating a Document is outside the DOM's spec,
141
* since it has to operate in terms of a particular implementation.
143
public DeferredDocumentImpl() {
148
* NON-DOM: Actually creating a Document is outside the DOM's spec,
149
* since it has to operate in terms of a particular implementation.
151
public DeferredDocumentImpl(boolean namespacesEnabled) {
152
this(namespacesEnabled, false);
155
/** Experimental constructor. */
156
public DeferredDocumentImpl(boolean namespaces, boolean grammarAccess) {
157
super(grammarAccess);
160
needsSyncChildren(true);
162
fNamespacesEnabled = namespaces;
164
} // <init>(boolean,boolean)
171
* Retrieve information describing the abilities of this particular
172
* DOM implementation. Intended to support applications that may be
173
* using DOMs retrieved from several different sources, potentially
174
* with different underlying representations.
176
public DOMImplementation getImplementation() {
177
// Currently implemented as a singleton, since it's hardcoded
178
// information anyway.
179
return DeferredDOMImplementationImpl.getDOMImplementation();
182
/** Returns the cached parser.getNamespaces() value.*/
183
boolean getNamespacesEnabled() {
184
return fNamespacesEnabled;
187
void setNamespacesEnabled(boolean enable) {
188
fNamespacesEnabled = enable;
191
// internal factory methods
193
/** Creates a document node in the table. */
194
public int createDeferredDocument() {
195
int nodeIndex = createNode(Node.DOCUMENT_NODE);
199
/** Creates a doctype. */
200
public int createDeferredDocumentType(String rootElementName,
201
String publicId, String systemId) {
204
int nodeIndex = createNode(Node.DOCUMENT_TYPE_NODE);
205
int chunk = nodeIndex >> CHUNK_SHIFT;
206
int index = nodeIndex & CHUNK_MASK;
208
// save name, public id, system id
209
setChunkValue(fNodeName, rootElementName, chunk, index);
210
setChunkValue(fNodeValue, publicId, chunk, index);
211
setChunkValue(fNodeURI, systemId, chunk, index);
216
} // createDeferredDocumentType(String,String,String):int
218
public void setInternalSubset(int doctypeIndex, String subset) {
219
int chunk = doctypeIndex >> CHUNK_SHIFT;
220
int index = doctypeIndex & CHUNK_MASK;
222
// create extra data node to store internal subset
223
int extraDataIndex = createNode(Node.DOCUMENT_TYPE_NODE);
224
int echunk = extraDataIndex >> CHUNK_SHIFT;
225
int eindex = extraDataIndex & CHUNK_MASK;
226
setChunkIndex(fNodeExtra, extraDataIndex, chunk, index);
227
setChunkValue(fNodeValue, subset, echunk, eindex);
230
/** Creates a notation in the table. */
231
public int createDeferredNotation(String notationName,
232
String publicId, String systemId, String baseURI) {
235
int nodeIndex = createNode(Node.NOTATION_NODE);
236
int chunk = nodeIndex >> CHUNK_SHIFT;
237
int index = nodeIndex & CHUNK_MASK;
240
// create extra data node
241
int extraDataIndex = createNode(Node.NOTATION_NODE);
242
int echunk = extraDataIndex >> CHUNK_SHIFT;
243
int eindex = extraDataIndex & CHUNK_MASK;
245
// save name, public id, system id, and notation name
246
setChunkValue(fNodeName, notationName, chunk, index);
247
setChunkValue(fNodeValue, publicId, chunk, index);
248
setChunkValue(fNodeURI, systemId, chunk, index);
250
// in extra data node set baseURI value
251
setChunkIndex(fNodeExtra, extraDataIndex, chunk, index);
252
setChunkValue(fNodeName, baseURI, echunk, eindex);
257
} // createDeferredNotation(String,String,String):int
259
/** Creates an entity in the table. */
260
public int createDeferredEntity(String entityName, String publicId,
261
String systemId, String notationName,
264
int nodeIndex = createNode(Node.ENTITY_NODE);
265
int chunk = nodeIndex >> CHUNK_SHIFT;
266
int index = nodeIndex & CHUNK_MASK;
268
// create extra data node
269
int extraDataIndex = createNode(Node.ENTITY_NODE);
270
int echunk = extraDataIndex >> CHUNK_SHIFT;
271
int eindex = extraDataIndex & CHUNK_MASK;
273
// save name, public id, system id, and notation name
274
setChunkValue(fNodeName, entityName, chunk, index);
275
setChunkValue(fNodeValue, publicId, chunk, index);
276
setChunkValue(fNodeURI, systemId, chunk, index);
277
setChunkIndex(fNodeExtra, extraDataIndex, chunk, index);
278
// set other values in the extra chunk
280
setChunkValue(fNodeName, notationName, echunk, eindex);
282
setChunkValue(fNodeValue, null, echunk, eindex);
284
setChunkValue(fNodeURI, null, echunk, eindex);
287
int extraDataIndex2 = createNode(Node.ENTITY_NODE);
288
int echunk2 = extraDataIndex2 >> CHUNK_SHIFT;
289
int eindex2 = extraDataIndex2 & CHUNK_MASK;
291
setChunkIndex(fNodeExtra, extraDataIndex2, echunk, eindex);
294
setChunkValue(fNodeName, baseURI, echunk2, eindex2);
299
} // createDeferredEntity(String,String,String,String):int
301
public String getDeferredEntityBaseURI (int entityIndex){
302
if (entityIndex != -1) {
303
int extraDataIndex = getNodeExtra(entityIndex, false);
304
extraDataIndex = getNodeExtra(extraDataIndex, false);
305
return getNodeName (extraDataIndex, false);
310
// DOM Level 3: setting encoding and version
311
public void setEntityInfo(int currentEntityDecl,
312
String version, String encoding){
313
int eNodeIndex = getNodeExtra(currentEntityDecl, false);
314
if (eNodeIndex !=-1) {
315
int echunk = eNodeIndex >> CHUNK_SHIFT;
316
int eindex = eNodeIndex & CHUNK_MASK;
317
setChunkValue(fNodeValue, version, echunk, eindex);
318
setChunkValue(fNodeURI, encoding, echunk, eindex);
322
// DOM Level 3: sets element TypeInfo
323
public void setTypeInfo(int elementNodeIndex, Object type) {
324
int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
325
int elementIndex = elementNodeIndex & CHUNK_MASK;
326
setChunkValue(fNodeValue, type, elementChunk, elementIndex);
332
* An attribute specifying the actual encoding of this document. This is
333
* <code>null</code> otherwise.
334
* <br> This attribute represents the property [character encoding scheme]
337
public void setInputEncoding(int currentEntityDecl, String value){
338
// get first extra data chunk
339
int nodeIndex = getNodeExtra(currentEntityDecl, false);
340
// get second extra data chunk
341
int extraDataIndex = getNodeExtra(nodeIndex, false);
343
int echunk = extraDataIndex >> CHUNK_SHIFT;
344
int eindex = extraDataIndex & CHUNK_MASK;
346
setChunkValue(fNodeValue, value, echunk, eindex);
350
/** Creates an entity reference node in the table. */
351
public int createDeferredEntityReference(String name, String baseURI) {
354
int nodeIndex = createNode(Node.ENTITY_REFERENCE_NODE);
355
int chunk = nodeIndex >> CHUNK_SHIFT;
356
int index = nodeIndex & CHUNK_MASK;
357
setChunkValue(fNodeName, name, chunk, index);
358
setChunkValue(fNodeValue, baseURI, chunk, index);
363
} // createDeferredEntityReference(String):int
367
* Creates an element node with a URI in the table and type information.
370
public int createDeferredElement(String elementURI, String elementName,
374
int elementNodeIndex = createNode(Node.ELEMENT_NODE);
375
int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
376
int elementIndex = elementNodeIndex & CHUNK_MASK;
377
setChunkValue(fNodeName, elementName, elementChunk, elementIndex);
378
setChunkValue(fNodeURI, elementURI, elementChunk, elementIndex);
379
setChunkValue(fNodeValue, type, elementChunk, elementIndex);
382
return elementNodeIndex;
384
} // createDeferredElement(String,String,Object):int
387
* Creates an element node in the table.
390
public int createDeferredElement(String elementName) {
391
return createDeferredElement(null, elementName);
395
* Creates an element node with a URI in the table.
397
public int createDeferredElement(String elementURI, String elementName) {
400
int elementNodeIndex = createNode(Node.ELEMENT_NODE);
401
int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
402
int elementIndex = elementNodeIndex & CHUNK_MASK;
403
setChunkValue(fNodeName, elementName, elementChunk, elementIndex);
404
setChunkValue(fNodeURI, elementURI, elementChunk, elementIndex);
407
return elementNodeIndex;
409
} // createDeferredElement(String,String):int
413
* This method is used by the DOMParser to create attributes.
414
* @param elementNodeIndex
423
public int setDeferredAttribute(int elementNodeIndex,
432
int attrNodeIndex = createDeferredAttribute(attrName, attrURI, attrValue, specified);
433
int attrChunk = attrNodeIndex >> CHUNK_SHIFT;
434
int attrIndex = attrNodeIndex & CHUNK_MASK;
435
// set attribute's parent to element
436
setChunkIndex(fNodeParent, elementNodeIndex, attrChunk, attrIndex);
438
int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
439
int elementIndex = elementNodeIndex & CHUNK_MASK;
441
// get element's last attribute
442
int lastAttrNodeIndex = getChunkIndex(fNodeExtra, elementChunk, elementIndex);
443
if (lastAttrNodeIndex != 0) {
444
// add link from new attribute to last attribute
445
setChunkIndex(fNodePrevSib, lastAttrNodeIndex, attrChunk, attrIndex);
447
// add link from element to new last attribute
448
setChunkIndex(fNodeExtra, attrNodeIndex, elementChunk, elementIndex);
450
int extra = getChunkIndex(fNodeExtra, attrChunk, attrIndex);
453
setChunkIndex(fNodeExtra, extra, attrChunk, attrIndex);
454
String value = getChunkValue(fNodeValue, attrChunk, attrIndex);
455
putIdentifier(value, elementNodeIndex);
457
// store type information
459
int extraDataIndex = createNode(DeferredNode.TYPE_NODE);
460
int echunk = extraDataIndex >> CHUNK_SHIFT;
461
int eindex = extraDataIndex & CHUNK_MASK;
463
setChunkIndex(fNodeLastChild, extraDataIndex, attrChunk, attrIndex);
464
setChunkValue(fNodeValue, type, echunk, eindex);
468
return attrNodeIndex;
472
* Sets an attribute on an element node.
475
public int setDeferredAttribute(int elementNodeIndex,
476
String attrName, String attrURI,
477
String attrValue, boolean specified) {
479
int attrNodeIndex = createDeferredAttribute(attrName, attrURI,
480
attrValue, specified);
481
int attrChunk = attrNodeIndex >> CHUNK_SHIFT;
482
int attrIndex = attrNodeIndex & CHUNK_MASK;
483
// set attribute's parent to element
484
setChunkIndex(fNodeParent, elementNodeIndex, attrChunk, attrIndex);
486
int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
487
int elementIndex = elementNodeIndex & CHUNK_MASK;
489
// get element's last attribute
490
int lastAttrNodeIndex = getChunkIndex(fNodeExtra,
491
elementChunk, elementIndex);
492
if (lastAttrNodeIndex != 0) {
493
// add link from new attribute to last attribute
494
setChunkIndex(fNodePrevSib, lastAttrNodeIndex,
495
attrChunk, attrIndex);
497
// add link from element to new last attribute
498
setChunkIndex(fNodeExtra, attrNodeIndex,
499
elementChunk, elementIndex);
502
return attrNodeIndex;
504
} // setDeferredAttribute(int,String,String,String,boolean):int
506
/** Creates an attribute in the table. */
507
public int createDeferredAttribute(String attrName, String attrValue,
509
return createDeferredAttribute(attrName, null, attrValue, specified);
512
/** Creates an attribute with a URI in the table. */
513
public int createDeferredAttribute(String attrName, String attrURI,
514
String attrValue, boolean specified) {
517
int nodeIndex = createNode(NodeImpl.ATTRIBUTE_NODE);
518
int chunk = nodeIndex >> CHUNK_SHIFT;
519
int index = nodeIndex & CHUNK_MASK;
520
setChunkValue(fNodeName, attrName, chunk, index);
521
setChunkValue(fNodeURI, attrURI, chunk, index);
522
setChunkValue(fNodeValue, attrValue, chunk, index);
523
int extra = specified ? SPECIFIED : 0;
524
setChunkIndex(fNodeExtra, extra, chunk, index);
529
} // createDeferredAttribute(String,String,String,boolean):int
531
/** Creates an element definition in the table.*/
532
public int createDeferredElementDefinition(String elementName) {
535
int nodeIndex = createNode(NodeImpl.ELEMENT_DEFINITION_NODE);
536
int chunk = nodeIndex >> CHUNK_SHIFT;
537
int index = nodeIndex & CHUNK_MASK;
538
setChunkValue(fNodeName, elementName, chunk, index);
543
} // createDeferredElementDefinition(String):int
545
/** Creates a text node in the table. */
546
public int createDeferredTextNode(String data,
547
boolean ignorableWhitespace) {
550
int nodeIndex = createNode(Node.TEXT_NODE);
551
int chunk = nodeIndex >> CHUNK_SHIFT;
552
int index = nodeIndex & CHUNK_MASK;
553
setChunkValue(fNodeValue, data, chunk, index);
554
// use extra to store ignorableWhitespace info
555
setChunkIndex(fNodeExtra, ignorableWhitespace ? 1 : 0, chunk, index);
560
} // createDeferredTextNode(String,boolean):int
562
/** Creates a CDATA section node in the table. */
563
public int createDeferredCDATASection(String data) {
566
int nodeIndex = createNode(Node.CDATA_SECTION_NODE);
567
int chunk = nodeIndex >> CHUNK_SHIFT;
568
int index = nodeIndex & CHUNK_MASK;
569
setChunkValue(fNodeValue, data, chunk, index);
574
} // createDeferredCDATASection(String):int
576
/** Creates a processing instruction node in the table. */
577
public int createDeferredProcessingInstruction(String target,
580
int nodeIndex = createNode(Node.PROCESSING_INSTRUCTION_NODE);
581
int chunk = nodeIndex >> CHUNK_SHIFT;
582
int index = nodeIndex & CHUNK_MASK;
583
setChunkValue(fNodeName, target, chunk, index);
584
setChunkValue(fNodeValue, data, chunk, index);
588
} // createDeferredProcessingInstruction(String,String):int
590
/** Creates a comment node in the table. */
591
public int createDeferredComment(String data) {
594
int nodeIndex = createNode(Node.COMMENT_NODE);
595
int chunk = nodeIndex >> CHUNK_SHIFT;
596
int index = nodeIndex & CHUNK_MASK;
597
setChunkValue(fNodeValue, data, chunk, index);
602
} // createDeferredComment(String):int
604
/** Creates a clone of the specified node. */
605
public int cloneNode(int nodeIndex, boolean deep) {
607
// clone immediate node
609
int nchunk = nodeIndex >> CHUNK_SHIFT;
610
int nindex = nodeIndex & CHUNK_MASK;
611
int nodeType = fNodeType[nchunk][nindex];
612
int cloneIndex = createNode((short)nodeType);
613
int cchunk = cloneIndex >> CHUNK_SHIFT;
614
int cindex = cloneIndex & CHUNK_MASK;
615
setChunkValue(fNodeName, fNodeName[nchunk][nindex], cchunk, cindex);
616
setChunkValue(fNodeValue, fNodeValue[nchunk][nindex], cchunk, cindex);
617
setChunkValue(fNodeURI, fNodeURI[nchunk][nindex], cchunk, cindex);
618
int extraIndex = fNodeExtra[nchunk][nindex];
619
if (extraIndex != -1) {
620
if (nodeType != Node.ATTRIBUTE_NODE && nodeType != Node.TEXT_NODE) {
621
extraIndex = cloneNode(extraIndex, false);
623
setChunkIndex(fNodeExtra, extraIndex, cchunk, cindex);
626
// clone and attach children
629
int childIndex = getLastChild(nodeIndex, false);
630
while (childIndex != -1) {
631
int clonedChildIndex = cloneNode(childIndex, deep);
632
insertBefore(cloneIndex, clonedChildIndex, prevIndex);
633
prevIndex = clonedChildIndex;
634
childIndex = getRealPrevSibling(childIndex, false);
640
// return cloned node index
643
} // cloneNode(int,boolean):int
645
/** Appends a child to the specified parent in the table. */
646
public void appendChild(int parentIndex, int childIndex) {
648
// append parent index
649
int pchunk = parentIndex >> CHUNK_SHIFT;
650
int pindex = parentIndex & CHUNK_MASK;
651
int cchunk = childIndex >> CHUNK_SHIFT;
652
int cindex = childIndex & CHUNK_MASK;
653
setChunkIndex(fNodeParent, parentIndex, cchunk, cindex);
655
// set previous sibling of new child
656
int olast = getChunkIndex(fNodeLastChild, pchunk, pindex);
657
setChunkIndex(fNodePrevSib, olast, cchunk, cindex);
659
// update parent's last child
660
setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex);
662
} // appendChild(int,int)
664
/** Adds an attribute node to the specified element. */
665
public int setAttributeNode(int elemIndex, int attrIndex) {
667
int echunk = elemIndex >> CHUNK_SHIFT;
668
int eindex = elemIndex & CHUNK_MASK;
669
int achunk = attrIndex >> CHUNK_SHIFT;
670
int aindex = attrIndex & CHUNK_MASK;
672
// see if this attribute is already here
673
String attrName = getChunkValue(fNodeName, achunk, aindex);
674
int oldAttrIndex = getChunkIndex(fNodeExtra, echunk, eindex);
678
while (oldAttrIndex != -1) {
679
oachunk = oldAttrIndex >> CHUNK_SHIFT;
680
oaindex = oldAttrIndex & CHUNK_MASK;
681
String oldAttrName = getChunkValue(fNodeName, oachunk, oaindex);
682
if (oldAttrName.equals(attrName)) {
685
nextIndex = oldAttrIndex;
686
oldAttrIndex = getChunkIndex(fNodePrevSib, oachunk, oaindex);
689
// remove old attribute
690
if (oldAttrIndex != -1) {
693
int prevIndex = getChunkIndex(fNodePrevSib, oachunk, oaindex);
694
if (nextIndex == -1) {
695
setChunkIndex(fNodeExtra, prevIndex, echunk, eindex);
698
int pchunk = nextIndex >> CHUNK_SHIFT;
699
int pindex = nextIndex & CHUNK_MASK;
700
setChunkIndex(fNodePrevSib, prevIndex, pchunk, pindex);
703
// remove connections to siblings
704
clearChunkIndex(fNodeType, oachunk, oaindex);
705
clearChunkValue(fNodeName, oachunk, oaindex);
706
clearChunkValue(fNodeValue, oachunk, oaindex);
707
clearChunkIndex(fNodeParent, oachunk, oaindex);
708
clearChunkIndex(fNodePrevSib, oachunk, oaindex);
710
clearChunkIndex(fNodeLastChild, oachunk, oaindex);
711
int atchunk = attrTextIndex >> CHUNK_SHIFT;
712
int atindex = attrTextIndex & CHUNK_MASK;
713
clearChunkIndex(fNodeType, atchunk, atindex);
714
clearChunkValue(fNodeValue, atchunk, atindex);
715
clearChunkIndex(fNodeParent, atchunk, atindex);
716
clearChunkIndex(fNodeLastChild, atchunk, atindex);
720
int prevIndex = getChunkIndex(fNodeExtra, echunk, eindex);
721
setChunkIndex(fNodeExtra, attrIndex, echunk, eindex);
722
setChunkIndex(fNodePrevSib, prevIndex, achunk, aindex);
727
} // setAttributeNode(int,int):int
730
/** Adds an attribute node to the specified element. */
731
public void setIdAttributeNode(int elemIndex, int attrIndex) {
733
int chunk = attrIndex >> CHUNK_SHIFT;
734
int index = attrIndex & CHUNK_MASK;
735
int extra = getChunkIndex(fNodeExtra, chunk, index);
737
setChunkIndex(fNodeExtra, extra, chunk, index);
739
String value = getChunkValue(fNodeValue, chunk, index);
740
putIdentifier(value, elemIndex);
744
/** Sets type of attribute */
745
public void setIdAttribute(int attrIndex) {
747
int chunk = attrIndex >> CHUNK_SHIFT;
748
int index = attrIndex & CHUNK_MASK;
749
int extra = getChunkIndex(fNodeExtra, chunk, index);
751
setChunkIndex(fNodeExtra, extra, chunk, index);
754
/** Inserts a child before the specified node in the table. */
755
public int insertBefore(int parentIndex, int newChildIndex, int refChildIndex) {
757
if (refChildIndex == -1) {
758
appendChild(parentIndex, newChildIndex);
759
return newChildIndex;
762
int nchunk = newChildIndex >> CHUNK_SHIFT;
763
int nindex = newChildIndex & CHUNK_MASK;
764
int rchunk = refChildIndex >> CHUNK_SHIFT;
765
int rindex = refChildIndex & CHUNK_MASK;
766
int previousIndex = getChunkIndex(fNodePrevSib, rchunk, rindex);
767
setChunkIndex(fNodePrevSib, newChildIndex, rchunk, rindex);
768
setChunkIndex(fNodePrevSib, previousIndex, nchunk, nindex);
770
return newChildIndex;
772
} // insertBefore(int,int,int):int
774
/** Sets the last child of the parentIndex to childIndex. */
775
public void setAsLastChild(int parentIndex, int childIndex) {
776
int pchunk = parentIndex >> CHUNK_SHIFT;
777
int pindex = parentIndex & CHUNK_MASK;
778
setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex);
779
} // setAsLastChild(int,int)
782
* Returns the parent node of the given node.
783
* <em>Calling this method does not free the parent index.</em>
785
public int getParentNode(int nodeIndex) {
786
return getParentNode(nodeIndex, false);
790
* Returns the parent node of the given node.
791
* @param free True to free parent node.
793
public int getParentNode(int nodeIndex, boolean free) {
795
if (nodeIndex == -1) {
799
int chunk = nodeIndex >> CHUNK_SHIFT;
800
int index = nodeIndex & CHUNK_MASK;
801
return free ? clearChunkIndex(fNodeParent, chunk, index)
802
: getChunkIndex(fNodeParent, chunk, index);
804
} // getParentNode(int):int
806
/** Returns the last child of the given node. */
807
public int getLastChild(int nodeIndex) {
808
return getLastChild(nodeIndex, true);
812
* Returns the last child of the given node.
813
* @param free True to free child index.
815
public int getLastChild(int nodeIndex, boolean free) {
817
if (nodeIndex == -1) {
821
int chunk = nodeIndex >> CHUNK_SHIFT;
822
int index = nodeIndex & CHUNK_MASK;
823
return free ? clearChunkIndex(fNodeLastChild, chunk, index)
824
: getChunkIndex(fNodeLastChild, chunk, index);
826
} // getLastChild(int,boolean):int
829
* Returns the prev sibling of the given node.
830
* This is post-normalization of Text Nodes.
832
public int getPrevSibling(int nodeIndex) {
833
return getPrevSibling(nodeIndex, true);
837
* Returns the prev sibling of the given node.
838
* @param free True to free sibling index.
840
public int getPrevSibling(int nodeIndex, boolean free) {
842
if (nodeIndex == -1) {
846
int chunk = nodeIndex >> CHUNK_SHIFT;
847
int index = nodeIndex & CHUNK_MASK;
848
int type = getChunkIndex(fNodeType, chunk, index);
849
if (type == Node.TEXT_NODE) {
851
nodeIndex = getChunkIndex(fNodePrevSib, chunk, index);
852
if (nodeIndex == -1) {
855
chunk = nodeIndex >> CHUNK_SHIFT;
856
index = nodeIndex & CHUNK_MASK;
857
type = getChunkIndex(fNodeType, chunk, index);
858
} while (type == Node.TEXT_NODE);
861
nodeIndex = getChunkIndex(fNodePrevSib, chunk, index);
866
} // getPrevSibling(int,boolean):int
869
* Returns the <i>real</i> prev sibling of the given node,
870
* directly from the data structures. Used by TextImpl#getNodeValue()
871
* to normalize values.
873
public int getRealPrevSibling(int nodeIndex) {
874
return getRealPrevSibling(nodeIndex, true);
878
* Returns the <i>real</i> prev sibling of the given node.
879
* @param free True to free sibling index.
881
public int getRealPrevSibling(int nodeIndex, boolean free) {
883
if (nodeIndex == -1) {
887
int chunk = nodeIndex >> CHUNK_SHIFT;
888
int index = nodeIndex & CHUNK_MASK;
889
return free ? clearChunkIndex(fNodePrevSib, chunk, index)
890
: getChunkIndex(fNodePrevSib, chunk, index);
892
} // getReadPrevSibling(int,boolean):int
895
* Returns the index of the element definition in the table
896
* with the specified name index, or -1 if no such definition
899
public int lookupElementDefinition(String elementName) {
901
if (fNodeCount > 1) {
904
int docTypeIndex = -1;
907
for (int index = getChunkIndex(fNodeLastChild, nchunk, nindex);
909
index = getChunkIndex(fNodePrevSib, nchunk, nindex)) {
911
nchunk = index >> CHUNK_SHIFT;
912
nindex = index & CHUNK_MASK;
913
if (getChunkIndex(fNodeType, nchunk, nindex) == Node.DOCUMENT_TYPE_NODE) {
914
docTypeIndex = index;
919
// find element definition
920
if (docTypeIndex == -1) {
923
nchunk = docTypeIndex >> CHUNK_SHIFT;
924
nindex = docTypeIndex & CHUNK_MASK;
925
for (int index = getChunkIndex(fNodeLastChild, nchunk, nindex);
927
index = getChunkIndex(fNodePrevSib, nchunk, nindex)) {
929
nchunk = index >> CHUNK_SHIFT;
930
nindex = index & CHUNK_MASK;
931
if (getChunkIndex(fNodeType, nchunk, nindex) ==
932
NodeImpl.ELEMENT_DEFINITION_NODE
933
&& getChunkValue(fNodeName, nchunk, nindex) == elementName) {
941
} // lookupElementDefinition(String):int
943
/** Instantiates the requested node object. */
944
public DeferredNode getNodeObject(int nodeIndex) {
946
// is there anything to do?
947
if (nodeIndex == -1) {
952
int chunk = nodeIndex >> CHUNK_SHIFT;
953
int index = nodeIndex & CHUNK_MASK;
954
int type = getChunkIndex(fNodeType, chunk, index);
955
if (type != Node.TEXT_NODE && type != Node.CDATA_SECTION_NODE) {
956
clearChunkIndex(fNodeType, chunk, index);
960
DeferredNode node = null;
964
// Standard DOM node types
967
case Node.ATTRIBUTE_NODE: {
968
if (fNamespacesEnabled) {
969
node = new DeferredAttrNSImpl(this, nodeIndex);
971
node = new DeferredAttrImpl(this, nodeIndex);
976
case Node.CDATA_SECTION_NODE: {
977
node = new DeferredCDATASectionImpl(this, nodeIndex);
981
case Node.COMMENT_NODE: {
982
node = new DeferredCommentImpl(this, nodeIndex);
986
// NOTE: Document fragments can never be "fast".
988
// The parser will never ask to create a document
989
// fragment during the parse. Document fragments
990
// are used by the application *after* the parse.
992
// case Node.DOCUMENT_FRAGMENT_NODE: { break; }
993
case Node.DOCUMENT_NODE: {
994
// this node is never "fast"
999
case Node.DOCUMENT_TYPE_NODE: {
1000
node = new DeferredDocumentTypeImpl(this, nodeIndex);
1001
// save the doctype node
1002
docType = (DocumentTypeImpl)node;
1006
case Node.ELEMENT_NODE: {
1009
System.out.println("getNodeObject(ELEMENT_NODE): "+nodeIndex);
1013
if (fNamespacesEnabled) {
1014
node = new DeferredElementNSImpl(this, nodeIndex);
1016
node = new DeferredElementImpl(this, nodeIndex);
1019
// check to see if this element needs to be
1020
// registered for its ID attributes
1021
if (fIdElement != null) {
1022
int idIndex = binarySearch(fIdElement, 0,
1023
fIdCount-1, nodeIndex);
1024
while (idIndex != -1) {
1027
System.out.println(" id index: "+idIndex);
1028
System.out.println(" fIdName["+idIndex+
1029
"]: "+fIdName[idIndex]);
1033
String name = fIdName[idIndex];
1036
System.out.println(" name: "+name);
1037
System.out.print("getNodeObject()#");
1039
putIdentifier0(name, (Element)node);
1040
fIdName[idIndex] = null;
1043
// continue if there are more IDs for
1045
if (idIndex + 1 < fIdCount &&
1046
fIdElement[idIndex + 1] == nodeIndex) {
1057
case Node.ENTITY_NODE: {
1058
node = new DeferredEntityImpl(this, nodeIndex);
1062
case Node.ENTITY_REFERENCE_NODE: {
1063
node = new DeferredEntityReferenceImpl(this, nodeIndex);
1067
case Node.NOTATION_NODE: {
1068
node = new DeferredNotationImpl(this, nodeIndex);
1072
case Node.PROCESSING_INSTRUCTION_NODE: {
1073
node = new DeferredProcessingInstructionImpl(this, nodeIndex);
1077
case Node.TEXT_NODE: {
1078
node = new DeferredTextImpl(this, nodeIndex);
1083
// non-standard DOM node types
1086
case NodeImpl.ELEMENT_DEFINITION_NODE: {
1087
node = new DeferredElementDefinitionImpl(this, nodeIndex);
1092
throw new IllegalArgumentException("type: "+type);
1095
} // switch node type
1103
throw new IllegalArgumentException();
1105
} // createNodeObject(int):Node
1107
/** Returns the name of the given node. */
1108
public String getNodeName(int nodeIndex) {
1109
return getNodeName(nodeIndex, true);
1110
} // getNodeNameString(int):String
1113
* Returns the name of the given node.
1114
* @param free True to free the string index.
1116
public String getNodeName(int nodeIndex, boolean free) {
1118
if (nodeIndex == -1) {
1122
int chunk = nodeIndex >> CHUNK_SHIFT;
1123
int index = nodeIndex & CHUNK_MASK;
1124
return free ? clearChunkValue(fNodeName, chunk, index)
1125
: getChunkValue(fNodeName, chunk, index);
1127
} // getNodeName(int,boolean):String
1129
/** Returns the real value of the given node. */
1130
public String getNodeValueString(int nodeIndex) {
1131
return getNodeValueString(nodeIndex, true);
1132
} // getNodeValueString(int):String
1135
* Returns the real value of the given node.
1136
* @param free True to free the string index.
1138
public String getNodeValueString(int nodeIndex, boolean free) {
1140
if (nodeIndex == -1) {
1144
int chunk = nodeIndex >> CHUNK_SHIFT;
1145
int index = nodeIndex & CHUNK_MASK;
1146
String value = free ? clearChunkValue(fNodeValue, chunk, index)
1147
: getChunkValue(fNodeValue, chunk, index);
1148
if (value == null) {
1152
int type = getChunkIndex(fNodeType, chunk, index);
1153
if (type == Node.TEXT_NODE) {
1154
int prevSib = getRealPrevSibling(nodeIndex);
1155
if (prevSib != -1 &&
1156
getNodeType(prevSib, false) == Node.TEXT_NODE) {
1157
// append data that is stored in fNodeValue
1158
// REVISIT: for text nodes it works differently than for CDATA
1160
fStrChunks.addElement(value);
1162
// go in reverse order: find last child, then
1163
// its previous sibling, etc
1164
chunk = prevSib >> CHUNK_SHIFT;
1165
index = prevSib & CHUNK_MASK;
1166
value = getChunkValue(fNodeValue, chunk, index);
1167
fStrChunks.addElement(value);
1168
prevSib = getChunkIndex(fNodePrevSib, chunk, index);
1169
if (prevSib == -1) {
1172
} while (getNodeType(prevSib, false) == Node.TEXT_NODE);
1174
int chunkCount = fStrChunks.size();
1176
// add to the buffer in the correct order.
1177
for (int i = chunkCount - 1; i >= 0; i--) {
1178
fBufferStr.append((String)fStrChunks.elementAt(i));
1181
value = fBufferStr.toString();
1182
fStrChunks.removeAllElements();
1183
fBufferStr.setLength(0);
1187
else if (type == Node.CDATA_SECTION_NODE) {
1188
// find if any other data stored in children
1189
int child = getLastChild(nodeIndex, false);
1191
// append data that is stored in fNodeValue
1192
fBufferStr.append(value);
1193
while (child !=-1) {
1194
// go in reverse order: find last child, then
1195
// its previous sibling, etc
1196
chunk = child >> CHUNK_SHIFT;
1197
index = child & CHUNK_MASK;
1198
value = getChunkValue(fNodeValue, chunk, index);
1199
fStrChunks.addElement(value);
1200
child = getChunkIndex(fNodePrevSib, chunk, index);
1202
// add to the buffer in the correct order.
1203
for (int i=fStrChunks.size()-1; i>=0; i--) {
1204
fBufferStr.append((String)fStrChunks.elementAt(i));
1207
value = fBufferStr.toString();
1208
fStrChunks.setSize(0);
1209
fBufferStr.setLength(0);
1216
} // getNodeValueString(int,boolean):String
1219
* Returns the value of the given node.
1221
public String getNodeValue(int nodeIndex) {
1222
return getNodeValue(nodeIndex, true);
1226
* Clears the type info that is stored in the fNodeValue array
1228
* @return Object - type information for the attribute/element node
1230
public Object getTypeInfo(int nodeIndex) {
1231
if (nodeIndex == -1) {
1235
int chunk = nodeIndex >> CHUNK_SHIFT;
1236
int index = nodeIndex & CHUNK_MASK;
1239
Object value = fNodeValue[chunk] != null ? fNodeValue[chunk][index] : null;
1240
if (value != null) {
1241
fNodeValue[chunk][index] = null;
1242
RefCount c = (RefCount) fNodeValue[chunk][CHUNK_SIZE];
1244
if (c.fCount == 0) {
1245
fNodeValue[chunk] = null;
1252
* Returns the value of the given node.
1253
* @param free True to free the value index.
1255
public String getNodeValue(int nodeIndex, boolean free) {
1257
if (nodeIndex == -1) {
1261
int chunk = nodeIndex >> CHUNK_SHIFT;
1262
int index = nodeIndex & CHUNK_MASK;
1263
return free ? clearChunkValue(fNodeValue, chunk, index)
1264
: getChunkValue(fNodeValue, chunk, index);
1266
} // getNodeValue(int,boolean):String
1269
* Returns the extra info of the given node.
1270
* Used by AttrImpl to store specified value (1 == true).
1272
public int getNodeExtra(int nodeIndex) {
1273
return getNodeExtra(nodeIndex, true);
1277
* Returns the extra info of the given node.
1278
* @param free True to free the value index.
1280
public int getNodeExtra(int nodeIndex, boolean free) {
1282
if (nodeIndex == -1) {
1286
int chunk = nodeIndex >> CHUNK_SHIFT;
1287
int index = nodeIndex & CHUNK_MASK;
1288
return free ? clearChunkIndex(fNodeExtra, chunk, index)
1289
: getChunkIndex(fNodeExtra, chunk, index);
1291
} // getNodeExtra(int,boolean):int
1293
/** Returns the type of the given node. */
1294
public short getNodeType(int nodeIndex) {
1295
return getNodeType(nodeIndex, true);
1299
* Returns the type of the given node.
1300
* @param free True to free type index.
1302
public short getNodeType(int nodeIndex, boolean free) {
1304
if (nodeIndex == -1) {
1308
int chunk = nodeIndex >> CHUNK_SHIFT;
1309
int index = nodeIndex & CHUNK_MASK;
1310
return free ? (short)clearChunkIndex(fNodeType, chunk, index)
1311
: (short)getChunkIndex(fNodeType, chunk, index);
1313
} // getNodeType(int):int
1315
/** Returns the attribute value of the given name. */
1316
public String getAttribute(int elemIndex, String name) {
1317
if (elemIndex == -1 || name == null) {
1320
int echunk = elemIndex >> CHUNK_SHIFT;
1321
int eindex = elemIndex & CHUNK_MASK;
1322
int attrIndex = getChunkIndex(fNodeExtra, echunk, eindex);
1323
while (attrIndex != -1) {
1324
int achunk = attrIndex >> CHUNK_SHIFT;
1325
int aindex = attrIndex & CHUNK_MASK;
1326
if (getChunkValue(fNodeName, achunk, aindex) == name) {
1327
return getChunkValue(fNodeValue, achunk, aindex);
1329
attrIndex = getChunkIndex(fNodePrevSib, achunk, aindex);
1334
/** Returns the URI of the given node. */
1335
public String getNodeURI(int nodeIndex) {
1336
return getNodeURI(nodeIndex, true);
1340
* Returns the URI of the given node.
1341
* @param free True to free URI index.
1343
public String getNodeURI(int nodeIndex, boolean free) {
1345
if (nodeIndex == -1) {
1349
int chunk = nodeIndex >> CHUNK_SHIFT;
1350
int index = nodeIndex & CHUNK_MASK;
1351
return free ? clearChunkValue(fNodeURI, chunk, index)
1352
: getChunkValue(fNodeURI, chunk, index);
1354
} // getNodeURI(int,int):String
1356
// identifier maintenance
1358
/** Registers an identifier name with a specified element node. */
1359
public void putIdentifier(String name, int elementNodeIndex) {
1362
System.out.println("putIdentifier(" + name + ", "
1363
+ elementNodeIndex + ')' + " // " +
1364
getChunkValue(fNodeName,
1365
elementNodeIndex >> CHUNK_SHIFT,
1366
elementNodeIndex & CHUNK_MASK));
1369
// initialize arrays
1370
if (fIdName == null) {
1371
fIdName = new String[64];
1372
fIdElement = new int[64];
1376
if (fIdCount == fIdName.length) {
1377
String idName[] = new String[fIdCount * 2];
1378
System.arraycopy(fIdName, 0, idName, 0, fIdCount);
1381
int idElement[] = new int[idName.length];
1382
System.arraycopy(fIdElement, 0, idElement, 0, fIdCount);
1383
fIdElement = idElement;
1387
fIdName[fIdCount] = name;
1388
fIdElement[fIdCount] = elementNodeIndex;
1391
} // putIdentifier(String,int)
1397
/** Prints out the tables. */
1398
public void print() {
1400
if (DEBUG_PRINT_REF_COUNTS) {
1401
System.out.print("num\t");
1402
System.out.print("type\t");
1403
System.out.print("name\t");
1404
System.out.print("val\t");
1405
System.out.print("par\t");
1406
System.out.print("lch\t");
1407
System.out.print("psib");
1408
System.out.println();
1409
for (int i = 0; i < fNodeType.length; i++) {
1410
if (fNodeType[i] != null) {
1412
System.out.print("--------");
1413
System.out.print("--------");
1414
System.out.print("--------");
1415
System.out.print("--------");
1416
System.out.print("--------");
1417
System.out.print("--------");
1418
System.out.print("--------");
1419
System.out.println();
1422
System.out.print(i);
1423
System.out.print('\t');
1424
switch (fNodeType[i][CHUNK_SIZE]) {
1425
case DocumentImpl.ELEMENT_DEFINITION_NODE: { System.out.print("EDef"); break; }
1426
case Node.DOCUMENT_NODE: { System.out.print("Doc"); break; }
1427
case Node.DOCUMENT_TYPE_NODE: { System.out.print("DType"); break; }
1428
case Node.COMMENT_NODE: { System.out.print("Com"); break; }
1429
case Node.PROCESSING_INSTRUCTION_NODE: { System.out.print("PI"); break; }
1430
case Node.ELEMENT_NODE: { System.out.print("Elem"); break; }
1431
case Node.ENTITY_NODE: { System.out.print("Ent"); break; }
1432
case Node.ENTITY_REFERENCE_NODE: { System.out.print("ERef"); break; }
1433
case Node.TEXT_NODE: { System.out.print("Text"); break; }
1434
case Node.ATTRIBUTE_NODE: { System.out.print("Attr"); break; }
1435
case DeferredNode.TYPE_NODE: { System.out.print("TypeInfo"); break; }
1436
default: { System.out.print("?"+fNodeType[i][CHUNK_SIZE]); }
1438
System.out.print('\t');
1439
System.out.print(fNodeName[i][CHUNK_SIZE]);
1440
System.out.print('\t');
1441
System.out.print(fNodeValue[i][CHUNK_SIZE]);
1442
System.out.print('\t');
1443
System.out.print(fNodeURI[i][CHUNK_SIZE]);
1444
System.out.print('\t');
1445
System.out.print(fNodeParent[i][CHUNK_SIZE]);
1446
System.out.print('\t');
1447
System.out.print(fNodeLastChild[i][CHUNK_SIZE]);
1448
System.out.print('\t');
1449
System.out.print(fNodePrevSib[i][CHUNK_SIZE]);
1450
System.out.print('\t');
1451
System.out.print(fNodeExtra[i][CHUNK_SIZE]);
1452
System.out.println();
1457
if (DEBUG_PRINT_TABLES) {
1458
// This assumes that the document is small
1459
System.out.println("# start table");
1460
for (int i = 0; i < fNodeCount; i++) {
1461
int chunk = i >> CHUNK_SHIFT;
1462
int index = i & CHUNK_MASK;
1464
System.out.print("num\t");
1465
System.out.print("type\t");
1466
System.out.print("name\t");
1467
System.out.print("val\t");
1468
System.out.print("uri\t");
1469
System.out.print("par\t");
1470
System.out.print("lch\t");
1471
System.out.print("psib\t");
1472
System.out.print("xtra");
1473
System.out.println();
1475
System.out.print(i);
1476
System.out.print('\t');
1477
switch (getChunkIndex(fNodeType, chunk, index)) {
1478
case DocumentImpl.ELEMENT_DEFINITION_NODE: { System.out.print("EDef"); break; }
1479
case Node.DOCUMENT_NODE: { System.out.print("Doc"); break; }
1480
case Node.DOCUMENT_TYPE_NODE: { System.out.print("DType"); break; }
1481
case Node.COMMENT_NODE: { System.out.print("Com"); break; }
1482
case Node.PROCESSING_INSTRUCTION_NODE: { System.out.print("PI"); break; }
1483
case Node.ELEMENT_NODE: { System.out.print("Elem"); break; }
1484
case Node.ENTITY_NODE: { System.out.print("Ent"); break; }
1485
case Node.ENTITY_REFERENCE_NODE: { System.out.print("ERef"); break; }
1486
case Node.TEXT_NODE: { System.out.print("Text"); break; }
1487
case Node.ATTRIBUTE_NODE: { System.out.print("Attr"); break; }
1488
case DeferredNode.TYPE_NODE: { System.out.print("TypeInfo"); break; }
1489
default: { System.out.print("?"+getChunkIndex(fNodeType, chunk, index)); }
1491
System.out.print('\t');
1492
System.out.print(getChunkValue(fNodeName, chunk, index));
1493
System.out.print('\t');
1494
System.out.print(getNodeValue(chunk, index));
1495
System.out.print('\t');
1496
System.out.print(getChunkValue(fNodeURI, chunk, index));
1497
System.out.print('\t');
1498
System.out.print(getChunkIndex(fNodeParent, chunk, index));
1499
System.out.print('\t');
1500
System.out.print(getChunkIndex(fNodeLastChild, chunk, index));
1501
System.out.print('\t');
1502
System.out.print(getChunkIndex(fNodePrevSib, chunk, index));
1503
System.out.print('\t');
1504
System.out.print(getChunkIndex(fNodeExtra, chunk, index));
1505
System.out.println();
1507
System.out.println("# end table");
1513
// DeferredNode methods
1516
/** Returns the node index. */
1517
public int getNodeIndex() {
1522
// Protected methods
1525
/** Synchronizes the node's data. */
1526
protected void synchronizeData() {
1528
// no need to sync in the future
1529
needsSyncData(false);
1531
// fluff up enough nodes to fill identifiers hash
1532
if (fIdElement != null) {
1534
// REVISIT: There has to be a more efficient way of
1535
// doing this. But keep in mind that the
1536
// tree can have been altered and re-ordered
1537
// before all of the element nodes with ID
1538
// attributes have been registered. For now
1539
// this is reasonable and safe. -Ac
1541
IntVector path = new IntVector();
1542
for (int i = 0; i < fIdCount; i++) {
1544
// ignore if it's already been registered
1545
int elementNodeIndex = fIdElement[i];
1546
String idName = fIdName[i];
1547
if (idName == null) {
1551
// find path from this element to the root
1552
path.removeAllElements();
1553
int index = elementNodeIndex;
1555
path.addElement(index);
1556
int pchunk = index >> CHUNK_SHIFT;
1557
int pindex = index & CHUNK_MASK;
1558
index = getChunkIndex(fNodeParent, pchunk, pindex);
1559
} while (index != -1);
1561
// Traverse path (backwards), fluffing the elements
1562
// along the way. When this loop finishes, "place"
1563
// will contain the reference to the element node
1564
// we're interested in. -Ac
1566
for (int j = path.size() - 2; j >= 0; j--) {
1567
index = path.elementAt(j);
1568
Node child = place.getLastChild();
1569
while (child != null) {
1570
if (child instanceof DeferredNode) {
1572
((DeferredNode)child).getNodeIndex();
1573
if (nodeIndex == index) {
1578
child = child.getPreviousSibling();
1582
// register the element
1583
Element element = (Element)place;
1584
putIdentifier0(idName, element);
1587
// see if there are more IDs on this element
1588
while (i + 1 < fIdCount &&
1589
fIdElement[i + 1] == elementNodeIndex) {
1590
idName = fIdName[++i];
1591
if (idName == null) {
1594
putIdentifier0(idName, element);
1600
} // synchronizeData()
1603
* Synchronizes the node's children with the internal structure.
1604
* Fluffing the children at once solves a lot of work to keep
1605
* the two structures in sync. The problem gets worse when
1606
* editing the tree -- this makes it a lot easier.
1608
protected void synchronizeChildren() {
1610
if (needsSyncData()) {
1613
* when we have elements with IDs this method is being recursively
1614
* called from synchronizeData, in which case we've already gone
1615
* through the following and we can now simply stop here.
1617
if (!needsSyncChildren()) {
1622
// we don't want to generate any event for this so turn them off
1623
boolean orig = mutationEvents;
1624
mutationEvents = false;
1626
// no need to sync in the future
1627
needsSyncChildren(false);
1631
// create children and link them as siblings
1632
ChildNode first = null;
1633
ChildNode last = null;
1634
for (int index = getLastChild(0);
1636
index = getPrevSibling(index)) {
1638
ChildNode node = (ChildNode)getNodeObject(index);
1643
first.previousSibling = node;
1645
node.ownerNode = this;
1647
node.nextSibling = first;
1650
// save doctype and document type
1651
int type = node.getNodeType();
1652
if (type == Node.ELEMENT_NODE) {
1653
docElement = (ElementImpl)node;
1655
else if (type == Node.DOCUMENT_TYPE_NODE) {
1656
docType = (DocumentTypeImpl)node;
1660
if (first != null) {
1662
first.isFirstChild(true);
1666
// set mutation events flag back to its original value
1667
mutationEvents = orig;
1669
} // synchronizeChildren()
1672
* Synchronizes the node's children with the internal structure.
1673
* Fluffing the children at once solves a lot of work to keep
1674
* the two structures in sync. The problem gets worse when
1675
* editing the tree -- this makes it a lot easier.
1676
* This is not directly used in this class but this method is
1677
* here so that it can be shared by all deferred subclasses of AttrImpl.
1679
protected final void synchronizeChildren(AttrImpl a, int nodeIndex) {
1681
// we don't want to generate any event for this so turn them off
1682
boolean orig = getMutationEvents();
1683
setMutationEvents(false);
1685
// no need to sync in the future
1686
a.needsSyncChildren(false);
1688
// create children and link them as siblings or simply store the value
1689
// as a String if all we have is one piece of text
1690
int last = getLastChild(nodeIndex);
1691
int prev = getPrevSibling(last);
1693
a.value = getNodeValueString(nodeIndex);
1694
a.hasStringValue(true);
1697
ChildNode firstNode = null;
1698
ChildNode lastNode = null;
1699
for (int index = last; index != -1;
1700
index = getPrevSibling(index)) {
1702
ChildNode node = (ChildNode) getNodeObject(index);
1703
if (lastNode == null) {
1707
firstNode.previousSibling = node;
1711
node.nextSibling = firstNode;
1714
if (lastNode != null) {
1715
a.value = firstNode; // firstChild = firstNode
1716
firstNode.isFirstChild(true);
1717
a.lastChild(lastNode);
1719
a.hasStringValue(false);
1722
// set mutation events flag back to its original value
1723
setMutationEvents(orig);
1725
} // synchronizeChildren(AttrImpl,int):void
1729
* Synchronizes the node's children with the internal structure.
1730
* Fluffing the children at once solves a lot of work to keep
1731
* the two structures in sync. The problem gets worse when
1732
* editing the tree -- this makes it a lot easier.
1733
* This is not directly used in this class but this method is
1734
* here so that it can be shared by all deferred subclasses of ParentNode.
1736
protected final void synchronizeChildren(ParentNode p, int nodeIndex) {
1738
// we don't want to generate any event for this so turn them off
1739
boolean orig = getMutationEvents();
1740
setMutationEvents(false);
1742
// no need to sync in the future
1743
p.needsSyncChildren(false);
1745
// create children and link them as siblings
1746
ChildNode firstNode = null;
1747
ChildNode lastNode = null;
1748
for (int index = getLastChild(nodeIndex);
1750
index = getPrevSibling(index)) {
1752
ChildNode node = (ChildNode) getNodeObject(index);
1753
if (lastNode == null) {
1757
firstNode.previousSibling = node;
1761
node.nextSibling = firstNode;
1764
if (lastNode != null) {
1765
p.firstChild = firstNode;
1766
firstNode.isFirstChild(true);
1767
p.lastChild(lastNode);
1770
// set mutation events flag back to its original value
1771
setMutationEvents(orig);
1773
} // synchronizeChildren(ParentNode,int):void
1777
/** Ensures that the internal tables are large enough. */
1778
protected void ensureCapacity(int chunk) {
1779
if (fNodeType == null) {
1781
fNodeType = new int[INITIAL_CHUNK_COUNT][];
1782
fNodeName = new Object[INITIAL_CHUNK_COUNT][];
1783
fNodeValue = new Object[INITIAL_CHUNK_COUNT][];
1784
fNodeParent = new int[INITIAL_CHUNK_COUNT][];
1785
fNodeLastChild = new int[INITIAL_CHUNK_COUNT][];
1786
fNodePrevSib = new int[INITIAL_CHUNK_COUNT][];
1787
fNodeURI = new Object[INITIAL_CHUNK_COUNT][];
1788
fNodeExtra = new int[INITIAL_CHUNK_COUNT][];
1790
else if (fNodeType.length <= chunk) {
1791
// resize the tables
1792
int newsize = chunk * 2;
1794
int[][] newArray = new int[newsize][];
1795
System.arraycopy(fNodeType, 0, newArray, 0, chunk);
1796
fNodeType = newArray;
1798
Object[][] newStrArray = new Object[newsize][];
1799
System.arraycopy(fNodeName, 0, newStrArray, 0, chunk);
1800
fNodeName = newStrArray;
1802
newStrArray = new Object[newsize][];
1803
System.arraycopy(fNodeValue, 0, newStrArray, 0, chunk);
1804
fNodeValue = newStrArray;
1806
newArray = new int[newsize][];
1807
System.arraycopy(fNodeParent, 0, newArray, 0, chunk);
1808
fNodeParent = newArray;
1810
newArray = new int[newsize][];
1811
System.arraycopy(fNodeLastChild, 0, newArray, 0, chunk);
1812
fNodeLastChild = newArray;
1814
newArray = new int[newsize][];
1815
System.arraycopy(fNodePrevSib, 0, newArray, 0, chunk);
1816
fNodePrevSib = newArray;
1818
newStrArray = new Object[newsize][];
1819
System.arraycopy(fNodeURI, 0, newStrArray, 0, chunk);
1820
fNodeURI = newStrArray;
1822
newArray = new int[newsize][];
1823
System.arraycopy(fNodeExtra, 0, newArray, 0, chunk);
1824
fNodeExtra = newArray;
1826
else if (fNodeType[chunk] != null) {
1827
// Done - there's sufficient capacity
1831
// create new chunks
1832
createChunk(fNodeType, chunk);
1833
createChunk(fNodeName, chunk);
1834
createChunk(fNodeValue, chunk);
1835
createChunk(fNodeParent, chunk);
1836
createChunk(fNodeLastChild, chunk);
1837
createChunk(fNodePrevSib, chunk);
1838
createChunk(fNodeURI, chunk);
1839
createChunk(fNodeExtra, chunk);
1844
} // ensureCapacity(int,int)
1846
/** Creates a node of the specified type. */
1847
protected int createNode(short nodeType) {
1848
// ensure tables are large enough
1849
int chunk = fNodeCount >> CHUNK_SHIFT;
1850
int index = fNodeCount & CHUNK_MASK;
1851
ensureCapacity(chunk);
1854
setChunkIndex(fNodeType, nodeType, chunk, index);
1856
// return node index number
1857
return fNodeCount++;
1859
} // createNode(short):int
1862
* Performs a binary search for a target value in an array of
1863
* values. The array of values must be in ascending sorted order
1864
* before calling this method and all array values must be
1867
* @param values The array of values to search.
1868
* @param start The starting offset of the search.
1869
* @param end The ending offset of the search.
1870
* @param target The target value.
1872
* @return This function will return the <i>first</i> occurrence
1873
* of the target value, or -1 if the target value cannot
1876
protected static int binarySearch(final int values[],
1877
int start, int end, int target) {
1880
System.out.println("binarySearch(), target: "+target);
1883
// look for target value
1884
while (start <= end) {
1886
// is this the one we're looking for?
1887
int middle = (start + end) / 2;
1888
int value = values[middle];
1890
System.out.print(" value: "+value+", target: "+target+" // ");
1891
print(values, start, end, middle, target);
1893
if (value == target) {
1894
while (middle > 0 && values[middle - 1] == target) {
1898
System.out.println("FOUND AT "+middle);
1903
// is this point higher or lower?
1904
if (value > target) {
1915
System.out.println("NOT FOUND!");
1919
} // binarySearch(int[],int,int,int):int
1924
private static final int[] INIT_ARRAY = new int[CHUNK_SIZE + 1];
1926
for (int i = 0; i < CHUNK_SIZE; i++) {
1930
/** Creates the specified chunk in the given array of chunks. */
1931
private final void createChunk(int data[][], int chunk) {
1932
data[chunk] = new int[CHUNK_SIZE + 1];
1933
System.arraycopy(INIT_ARRAY, 0, data[chunk], 0, CHUNK_SIZE);
1936
static final class RefCount {
1940
private final void createChunk(Object data[][], int chunk) {
1941
data[chunk] = new Object[CHUNK_SIZE + 1];
1942
data[chunk][CHUNK_SIZE] = new RefCount();
1946
* Sets the specified value in the given of data at the chunk and index.
1948
* @return Returns the old value.
1950
private final int setChunkIndex(int data[][], int value,
1951
int chunk, int index) {
1953
return clearChunkIndex(data, chunk, index);
1955
int [] dataChunk = data[chunk];
1956
// Re-create chunk if it was deleted.
1957
if (dataChunk == null) {
1958
createChunk(data, chunk);
1959
dataChunk = data[chunk];
1961
int ovalue = dataChunk[index];
1963
dataChunk[CHUNK_SIZE]++;
1965
dataChunk[index] = value;
1968
private final String setChunkValue(Object data[][], Object value,
1969
int chunk, int index) {
1970
if (value == null) {
1971
return clearChunkValue(data, chunk, index);
1973
Object [] dataChunk = data[chunk];
1974
// Re-create chunk if it was deleted.
1975
if (dataChunk == null) {
1976
createChunk(data, chunk);
1977
dataChunk = data[chunk];
1979
String ovalue = (String) dataChunk[index];
1980
if (ovalue == null) {
1981
RefCount c = (RefCount) dataChunk[CHUNK_SIZE];
1984
dataChunk[index] = value;
1989
* Returns the specified value in the given data at the chunk and index.
1991
private final int getChunkIndex(int data[][], int chunk, int index) {
1992
return data[chunk] != null ? data[chunk][index] : -1;
1994
private final String getChunkValue(Object data[][], int chunk, int index) {
1995
return data[chunk] != null ? (String) data[chunk][index] : null;
1997
private final String getNodeValue(int chunk, int index) {
1998
Object data = fNodeValue[chunk][index];
2002
else if (data instanceof String){
2003
return (String)data;
2007
return data.toString();
2013
* Clears the specified value in the given data at the chunk and index.
2014
* Note that this method will clear the given chunk if the reference
2015
* count becomes zero.
2017
* @return Returns the old value.
2019
private final int clearChunkIndex(int data[][], int chunk, int index) {
2020
int value = data[chunk] != null ? data[chunk][index] : -1;
2022
data[chunk][CHUNK_SIZE]--;
2023
data[chunk][index] = -1;
2024
if (data[chunk][CHUNK_SIZE] == 0) {
2030
private final String clearChunkValue(Object data[][],
2031
int chunk, int index) {
2032
String value = data[chunk] != null ? (String)data[chunk][index] : null;
2033
if (value != null) {
2034
data[chunk][index] = null;
2035
RefCount c = (RefCount) data[chunk][CHUNK_SIZE];
2037
if (c.fCount == 0) {
2045
* This version of putIdentifier is needed to avoid fluffing
2046
* all of the paths to ID attributes when a node object is
2047
* created that contains an ID attribute.
2049
private final void putIdentifier0(String idName, Element element) {
2052
System.out.println("putIdentifier0("+
2058
if (identifiers == null) {
2059
identifiers = new java.util.Hashtable();
2062
// save ID and its associated element
2063
identifiers.put(idName, element);
2065
} // putIdentifier0(String,Element)
2067
/** Prints the ID array. */
2068
private static void print(int values[], int start, int end,
2069
int middle, int target) {
2072
System.out.print(start);
2073
System.out.print(" [");
2074
for (int i = start; i < end; i++) {
2076
System.out.print("!");
2078
System.out.print(values[i]);
2079
if (values[i] == target) {
2080
System.out.print("*");
2083
System.out.print(" ");
2086
System.out.println("] "+end);
2089
} // print(int[],int,int,int,int)
2096
* A simple integer vector.
2098
static final class IntVector {
2114
/** Returns the length of this vector. */
2119
/** Returns the element at the specified index. */
2120
public int elementAt(int index) {
2124
/** Appends an element to the end of the vector. */
2125
public void addElement(int element) {
2126
ensureCapacity(size + 1);
2127
data[size++] = element;
2130
/** Clears the vector. */
2131
public void removeAllElements() {
2139
/** Makes sure that there is enough storage. */
2140
private void ensureCapacity(int newsize) {
2143
data = new int[newsize + 15];
2145
else if (newsize > data.length) {
2146
int newdata[] = new int[newsize + 15];
2147
System.arraycopy(data, 0, newdata, 0, data.length);
2151
} // ensureCapacity(int)
2153
} // class IntVector
2155
} // class DeferredDocumentImpl