1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999-2002 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. package com.sun.org.apache.xerces.internal.dom;
  58. import org.w3c.dom.Element;
  59. import org.w3c.dom.Node;
  60. import org.w3c.dom.TypeInfo;
  61. import java.util.Vector;
  62. /**
  63. * The Document interface represents the entire HTML or XML document.
  64. * Conceptually, it is the root of the document tree, and provides the
  65. * primary access to the document's data.
  66. * <P>
  67. * Since elements, text nodes, comments, processing instructions,
  68. * etc. cannot exist outside the context of a Document, the Document
  69. * interface also contains the factory methods needed to create these
  70. * objects. The Node objects created have a ownerDocument attribute
  71. * which associates them with the Document within whose context they
  72. * were created.
  73. *
  74. <<<<<<< DeferredDocumentImpl.java
  75. * @version $Id: DeferredDocumentImpl.java,v 1.3 2003/11/18 00:22:50 kk122374 Exp $
  76. =======
  77. * @version $Id: DeferredDocumentImpl.java,v 1.3 2003/11/18 00:22:50 kk122374 Exp $
  78. >>>>>>> 1.1.1.2
  79. * @since PR-DOM-Level-1-19980818.
  80. */
  81. public class DeferredDocumentImpl
  82. extends DocumentImpl
  83. implements DeferredNode {
  84. //
  85. // Constants
  86. //
  87. /** Serialization version. */
  88. static final long serialVersionUID = 5186323580749626857L;
  89. // debugging
  90. /** To include code for printing the ref count tables. */
  91. private static final boolean DEBUG_PRINT_REF_COUNTS = false;
  92. /** To include code for printing the internal tables. */
  93. private static final boolean DEBUG_PRINT_TABLES = false;
  94. /** To debug identifiers set to true and recompile. */
  95. private static final boolean DEBUG_IDS = false;
  96. // protected
  97. /** Chunk shift. */
  98. protected static final int CHUNK_SHIFT = 11; // 2^11 = 2k
  99. /** Chunk size. */
  100. protected static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
  101. /** Chunk mask. */
  102. protected static final int CHUNK_MASK = CHUNK_SIZE - 1;
  103. /** Initial chunk size. */
  104. protected static final int INITIAL_CHUNK_COUNT = (1 << (16 - CHUNK_SHIFT)); // 2^16 = 64k
  105. //
  106. // Data
  107. //
  108. // lazy-eval information
  109. // To maximize memory consumption the actual semantic of these fields vary
  110. // depending on the node type.
  111. /** Node count. */
  112. protected transient int fNodeCount = 0;
  113. /** Node types. */
  114. protected transient int fNodeType[][];
  115. /** Node names. */
  116. protected transient Object fNodeName[][];
  117. /** Node values. */
  118. protected transient Object fNodeValue[][];
  119. /** Node parents. */
  120. protected transient int fNodeParent[][];
  121. /** Node first children. */
  122. protected transient int fNodeLastChild[][];
  123. /** Node prev siblings. */
  124. protected transient int fNodePrevSib[][];
  125. /** Node namespace URI. */
  126. protected transient Object fNodeURI[][];
  127. /** Extra data. */
  128. protected transient int fNodeExtra[][];
  129. /** Identifier count. */
  130. protected transient int fIdCount;
  131. /** Identifier name indexes. */
  132. protected transient String fIdName[];
  133. /** Identifier element indexes. */
  134. protected transient int fIdElement[];
  135. /** DOM2: For namespace support in the deferred case.
  136. */
  137. // Implementation Note: The deferred element and attribute must know how to
  138. // interpret the int representing the qname.
  139. protected boolean fNamespacesEnabled = false;
  140. //
  141. // private data
  142. //
  143. private transient final StringBuffer fBufferStr = new StringBuffer();
  144. private transient final Vector fStrChunks = new Vector();
  145. //
  146. // Constructors
  147. //
  148. /**
  149. * NON-DOM: Actually creating a Document is outside the DOM's spec,
  150. * since it has to operate in terms of a particular implementation.
  151. */
  152. public DeferredDocumentImpl() {
  153. this(false);
  154. } // <init>()
  155. /**
  156. * NON-DOM: Actually creating a Document is outside the DOM's spec,
  157. * since it has to operate in terms of a particular implementation.
  158. */
  159. public DeferredDocumentImpl(boolean namespacesEnabled) {
  160. this(namespacesEnabled, false);
  161. } // <init>(boolean)
  162. /** Experimental constructor. */
  163. public DeferredDocumentImpl(boolean namespaces, boolean grammarAccess) {
  164. super(grammarAccess);
  165. needsSyncData(true);
  166. needsSyncChildren(true);
  167. fNamespacesEnabled = namespaces;
  168. } // <init>(boolean,boolean)
  169. //
  170. // Public methods
  171. //
  172. /** Returns the cached parser.getNamespaces() value.*/
  173. boolean getNamespacesEnabled() {
  174. return fNamespacesEnabled;
  175. }
  176. void setNamespacesEnabled(boolean enable) {
  177. fNamespacesEnabled = enable;
  178. }
  179. // internal factory methods
  180. /** Creates a document node in the table. */
  181. public int createDeferredDocument() {
  182. int nodeIndex = createNode(Node.DOCUMENT_NODE);
  183. return nodeIndex;
  184. }
  185. /** Creates a doctype. */
  186. public int createDeferredDocumentType(String rootElementName,
  187. String publicId, String systemId) {
  188. // create node
  189. int nodeIndex = createNode(Node.DOCUMENT_TYPE_NODE);
  190. int chunk = nodeIndex >> CHUNK_SHIFT;
  191. int index = nodeIndex & CHUNK_MASK;
  192. // save name, public id, system id
  193. setChunkValue(fNodeName, rootElementName, chunk, index);
  194. setChunkValue(fNodeValue, publicId, chunk, index);
  195. setChunkValue(fNodeURI, systemId, chunk, index);
  196. // return node index
  197. return nodeIndex;
  198. } // createDeferredDocumentType(String,String,String):int
  199. public void setInternalSubset(int doctypeIndex, String subset) {
  200. int chunk = doctypeIndex >> CHUNK_SHIFT;
  201. int index = doctypeIndex & CHUNK_MASK;
  202. // create extra data node to store internal subset
  203. int extraDataIndex = createNode(Node.DOCUMENT_TYPE_NODE);
  204. int echunk = extraDataIndex >> CHUNK_SHIFT;
  205. int eindex = extraDataIndex & CHUNK_MASK;
  206. setChunkIndex(fNodeExtra, extraDataIndex, chunk, index);
  207. setChunkValue(fNodeValue, subset, echunk, eindex);
  208. }
  209. /** Creates a notation in the table. */
  210. public int createDeferredNotation(String notationName,
  211. String publicId, String systemId, String baseURI) {
  212. // create node
  213. int nodeIndex = createNode(Node.NOTATION_NODE);
  214. int chunk = nodeIndex >> CHUNK_SHIFT;
  215. int index = nodeIndex & CHUNK_MASK;
  216. // create extra data node
  217. int extraDataIndex = createNode(Node.NOTATION_NODE);
  218. int echunk = extraDataIndex >> CHUNK_SHIFT;
  219. int eindex = extraDataIndex & CHUNK_MASK;
  220. // save name, public id, system id, and notation name
  221. setChunkValue(fNodeName, notationName, chunk, index);
  222. setChunkValue(fNodeValue, publicId, chunk, index);
  223. setChunkValue(fNodeURI, systemId, chunk, index);
  224. // in extra data node set baseURI value
  225. setChunkIndex(fNodeExtra, extraDataIndex, chunk, index);
  226. setChunkValue(fNodeName, baseURI, echunk, eindex);
  227. // return node index
  228. return nodeIndex;
  229. } // createDeferredNotation(String,String,String):int
  230. /** Creates an entity in the table. */
  231. public int createDeferredEntity(String entityName, String publicId,
  232. String systemId, String notationName,
  233. String baseURI) {
  234. // create node
  235. int nodeIndex = createNode(Node.ENTITY_NODE);
  236. int chunk = nodeIndex >> CHUNK_SHIFT;
  237. int index = nodeIndex & CHUNK_MASK;
  238. // create extra data node
  239. int extraDataIndex = createNode(Node.ENTITY_NODE);
  240. int echunk = extraDataIndex >> CHUNK_SHIFT;
  241. int eindex = extraDataIndex & CHUNK_MASK;
  242. // save name, public id, system id, and notation name
  243. setChunkValue(fNodeName, entityName, chunk, index);
  244. setChunkValue(fNodeValue, publicId, chunk, index);
  245. setChunkValue(fNodeURI, systemId, chunk, index);
  246. setChunkIndex(fNodeExtra, extraDataIndex, chunk, index);
  247. // set other values in the extra chunk
  248. // notation
  249. setChunkValue(fNodeName, notationName, echunk, eindex);
  250. // version L3
  251. setChunkValue(fNodeValue, null, echunk, eindex);
  252. // encoding L3
  253. setChunkValue(fNodeURI, null, echunk, eindex);
  254. int extraDataIndex2 = createNode(Node.ENTITY_NODE);
  255. int echunk2 = extraDataIndex2 >> CHUNK_SHIFT;
  256. int eindex2 = extraDataIndex2 & CHUNK_MASK;
  257. setChunkIndex(fNodeExtra, extraDataIndex2, echunk, eindex);
  258. // baseURI
  259. setChunkValue(fNodeName, baseURI, echunk2, eindex2);
  260. // return node index
  261. return nodeIndex;
  262. } // createDeferredEntity(String,String,String,String):int
  263. public String getDeferredEntityBaseURI (int entityIndex){
  264. if (entityIndex != -1) {
  265. int extraDataIndex = getNodeExtra(entityIndex, false);
  266. extraDataIndex = getNodeExtra(extraDataIndex, false);
  267. return getNodeName (extraDataIndex, false);
  268. }
  269. return null;
  270. }
  271. // DOM Level 3: setting encoding and version
  272. public void setEntityInfo(int currentEntityDecl,
  273. String version, String encoding){
  274. int eNodeIndex = getNodeExtra(currentEntityDecl, false);
  275. if (eNodeIndex !=-1) {
  276. int echunk = eNodeIndex >> CHUNK_SHIFT;
  277. int eindex = eNodeIndex & CHUNK_MASK;
  278. setChunkValue(fNodeValue, version, echunk, eindex);
  279. setChunkValue(fNodeURI, encoding, echunk, eindex);
  280. }
  281. }
  282. /**
  283. * DOM Internal
  284. *
  285. * An attribute specifying the actual encoding of this document. This is
  286. * <code>null</code> otherwise.
  287. * <br> This attribute represents the property [character encoding scheme]
  288. * defined in .
  289. */
  290. public void setInputEncoding(int currentEntityDecl, String value){
  291. // get first extra data chunk
  292. int nodeIndex = getNodeExtra(currentEntityDecl, false);
  293. // get second extra data chunk
  294. int extraDataIndex = getNodeExtra(nodeIndex, false);
  295. int echunk = extraDataIndex >> CHUNK_SHIFT;
  296. int eindex = extraDataIndex & CHUNK_MASK;
  297. setChunkValue(fNodeValue, value, echunk, eindex);
  298. }
  299. /** Creates an entity reference node in the table. */
  300. public int createDeferredEntityReference(String name, String baseURI) {
  301. // create node
  302. int nodeIndex = createNode(Node.ENTITY_REFERENCE_NODE);
  303. int chunk = nodeIndex >> CHUNK_SHIFT;
  304. int index = nodeIndex & CHUNK_MASK;
  305. setChunkValue(fNodeName, name, chunk, index);
  306. setChunkValue(fNodeValue, baseURI, chunk, index);
  307. // return node index
  308. return nodeIndex;
  309. } // createDeferredEntityReference(String):int
  310. /** Creates an element node with a URI in the table and type information. */
  311. public int createDeferredElement(String elementURI, String elementName,
  312. TypeInfo type) {
  313. // create node
  314. int elementNodeIndex = createNode(Node.ELEMENT_NODE);
  315. int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
  316. int elementIndex = elementNodeIndex & CHUNK_MASK;
  317. setChunkValue(fNodeName, elementName, elementChunk, elementIndex);
  318. setChunkValue(fNodeURI, elementURI, elementChunk, elementIndex);
  319. setChunkValue(fNodeValue, type, elementChunk, elementIndex);
  320. // return node index
  321. return elementNodeIndex;
  322. } // createDeferredElement(String,String):int
  323. /** @deprecated. Creates an element node in the table. */
  324. public int createDeferredElement(String elementName) {
  325. return createDeferredElement(null, elementName);
  326. }
  327. /** @deprecated. Creates an element node with a URI in the table. */
  328. public int createDeferredElement(String elementURI, String elementName) {
  329. // create node
  330. int elementNodeIndex = createNode(Node.ELEMENT_NODE);
  331. int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
  332. int elementIndex = elementNodeIndex & CHUNK_MASK;
  333. setChunkValue(fNodeName, elementName, elementChunk, elementIndex);
  334. setChunkValue(fNodeURI, elementURI, elementChunk, elementIndex);
  335. // return node index
  336. return elementNodeIndex;
  337. } // createDeferredElement(String,String):int
  338. /**
  339. * This method is used by the DOMParser to create attributes.
  340. * @param elementNodeIndex
  341. * @param attrName
  342. * @param attrURI
  343. * @param attrValue
  344. * @param specified
  345. * @param id
  346. * @param type
  347. * @return int
  348. */
  349. public int setDeferredAttribute(int elementNodeIndex,
  350. String attrName,
  351. String attrURI,
  352. String attrValue,
  353. boolean specified,
  354. boolean id,
  355. TypeInfo type) {
  356. // create attribute
  357. int attrNodeIndex = createDeferredAttribute(attrName, attrURI, attrValue, specified);
  358. int attrChunk = attrNodeIndex >> CHUNK_SHIFT;
  359. int attrIndex = attrNodeIndex & CHUNK_MASK;
  360. // set attribute's parent to element
  361. setChunkIndex(fNodeParent, elementNodeIndex, attrChunk, attrIndex);
  362. int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
  363. int elementIndex = elementNodeIndex & CHUNK_MASK;
  364. // get element's last attribute
  365. int lastAttrNodeIndex = getChunkIndex(fNodeExtra, elementChunk, elementIndex);
  366. if (lastAttrNodeIndex != 0) {
  367. int lastAttrChunk = lastAttrNodeIndex >> CHUNK_SHIFT;
  368. int lastAttrIndex = lastAttrNodeIndex & CHUNK_MASK;
  369. // add link from new attribute to last attribute
  370. setChunkIndex(fNodePrevSib, lastAttrNodeIndex, attrChunk, attrIndex);
  371. }
  372. // add link from element to new last attribute
  373. setChunkIndex(fNodeExtra, attrNodeIndex, elementChunk, elementIndex);
  374. int extra = getChunkIndex(fNodeExtra, attrChunk, attrIndex);
  375. if (id) {
  376. extra = extra | ID;
  377. setChunkIndex(fNodeExtra, extra, attrChunk, attrIndex);
  378. String value = getChunkValue(fNodeValue, attrChunk, attrIndex);
  379. putIdentifier(value, elementNodeIndex);
  380. }
  381. // store type information
  382. if (type != null) {
  383. int extraDataIndex = createNode(DeferredNode.TYPE_NODE);
  384. int echunk = extraDataIndex >> CHUNK_SHIFT;
  385. int eindex = extraDataIndex & CHUNK_MASK;
  386. setChunkIndex(fNodeLastChild, extraDataIndex, attrChunk, attrIndex);
  387. setChunkValue(fNodeValue, type, echunk, eindex);
  388. }
  389. // return node index
  390. return attrNodeIndex;
  391. }
  392. /** @deprecated. Sets an attribute on an element node.*/
  393. public int setDeferredAttribute(int elementNodeIndex,
  394. String attrName, String attrURI,
  395. String attrValue, boolean specified) {
  396. // create attribute
  397. int attrNodeIndex = createDeferredAttribute(attrName, attrURI,
  398. attrValue, specified);
  399. int attrChunk = attrNodeIndex >> CHUNK_SHIFT;
  400. int attrIndex = attrNodeIndex & CHUNK_MASK;
  401. // set attribute's parent to element
  402. setChunkIndex(fNodeParent, elementNodeIndex, attrChunk, attrIndex);
  403. int elementChunk = elementNodeIndex >> CHUNK_SHIFT;
  404. int elementIndex = elementNodeIndex & CHUNK_MASK;
  405. // get element's last attribute
  406. int lastAttrNodeIndex = getChunkIndex(fNodeExtra,
  407. elementChunk, elementIndex);
  408. if (lastAttrNodeIndex != 0) {
  409. int lastAttrChunk = lastAttrNodeIndex >> CHUNK_SHIFT;
  410. int lastAttrIndex = lastAttrNodeIndex & CHUNK_MASK;
  411. // add link from new attribute to last attribute
  412. setChunkIndex(fNodePrevSib, lastAttrNodeIndex,
  413. attrChunk, attrIndex);
  414. }
  415. // add link from element to new last attribute
  416. setChunkIndex(fNodeExtra, attrNodeIndex,
  417. elementChunk, elementIndex);
  418. // return node index
  419. return attrNodeIndex;
  420. } // setDeferredAttribute(int,String,String,String,boolean):int
  421. /** Creates an attribute in the table. */
  422. public int createDeferredAttribute(String attrName, String attrValue,
  423. boolean specified) {
  424. return createDeferredAttribute(attrName, null, attrValue, specified);
  425. }
  426. /** Creates an attribute with a URI in the table. */
  427. public int createDeferredAttribute(String attrName, String attrURI,
  428. String attrValue, boolean specified) {
  429. // create node
  430. int nodeIndex = createNode(NodeImpl.ATTRIBUTE_NODE);
  431. int chunk = nodeIndex >> CHUNK_SHIFT;
  432. int index = nodeIndex & CHUNK_MASK;
  433. setChunkValue(fNodeName, attrName, chunk, index);
  434. setChunkValue(fNodeURI, attrURI, chunk, index);
  435. setChunkValue(fNodeValue, attrValue, chunk, index);
  436. int extra = specified ? SPECIFIED : 0;
  437. setChunkIndex(fNodeExtra, extra, chunk, index);
  438. // return node index
  439. return nodeIndex;
  440. } // createDeferredAttribute(String,String,String,boolean):int
  441. /** Creates an element definition in the table.*/
  442. public int createDeferredElementDefinition(String elementName) {
  443. // create node
  444. int nodeIndex = createNode(NodeImpl.ELEMENT_DEFINITION_NODE);
  445. int chunk = nodeIndex >> CHUNK_SHIFT;
  446. int index = nodeIndex & CHUNK_MASK;
  447. setChunkValue(fNodeName, elementName, chunk, index);
  448. // return node index
  449. return nodeIndex;
  450. } // createDeferredElementDefinition(String):int
  451. /** Creates a text node in the table. */
  452. public int createDeferredTextNode(String data,
  453. boolean ignorableWhitespace) {
  454. // create node
  455. int nodeIndex = createNode(Node.TEXT_NODE);
  456. int chunk = nodeIndex >> CHUNK_SHIFT;
  457. int index = nodeIndex & CHUNK_MASK;
  458. setChunkValue(fNodeValue, data, chunk, index);
  459. // use extra to store ignorableWhitespace info
  460. setChunkIndex(fNodeExtra, ignorableWhitespace ? 1 : 0, chunk, index);
  461. // return node index
  462. return nodeIndex;
  463. } // createDeferredTextNode(String,boolean):int
  464. /** Creates a CDATA section node in the table. */
  465. public int createDeferredCDATASection(String data) {
  466. // create node
  467. int nodeIndex = createNode(Node.CDATA_SECTION_NODE);
  468. int chunk = nodeIndex >> CHUNK_SHIFT;
  469. int index = nodeIndex & CHUNK_MASK;
  470. setChunkValue(fNodeValue, data, chunk, index);
  471. // return node index
  472. return nodeIndex;
  473. } // createDeferredCDATASection(String):int
  474. /** Creates a processing instruction node in the table. */
  475. public int createDeferredProcessingInstruction(String target,
  476. String data) {
  477. // create node
  478. int nodeIndex = createNode(Node.PROCESSING_INSTRUCTION_NODE);
  479. int chunk = nodeIndex >> CHUNK_SHIFT;
  480. int index = nodeIndex & CHUNK_MASK;
  481. setChunkValue(fNodeName, target, chunk, index);
  482. setChunkValue(fNodeValue, data, chunk, index);
  483. // return node index
  484. return nodeIndex;
  485. } // createDeferredProcessingInstruction(String,String):int
  486. /** Creates a comment node in the table. */
  487. public int createDeferredComment(String data) {
  488. // create node
  489. int nodeIndex = createNode(Node.COMMENT_NODE);
  490. int chunk = nodeIndex >> CHUNK_SHIFT;
  491. int index = nodeIndex & CHUNK_MASK;
  492. setChunkValue(fNodeValue, data, chunk, index);
  493. // return node index
  494. return nodeIndex;
  495. } // createDeferredComment(String):int
  496. /** Creates a clone of the specified node. */
  497. public int cloneNode(int nodeIndex, boolean deep) {
  498. // clone immediate node
  499. int nchunk = nodeIndex >> CHUNK_SHIFT;
  500. int nindex = nodeIndex & CHUNK_MASK;
  501. int nodeType = fNodeType[nchunk][nindex];
  502. int cloneIndex = createNode((short)nodeType);
  503. int cchunk = cloneIndex >> CHUNK_SHIFT;
  504. int cindex = cloneIndex & CHUNK_MASK;
  505. setChunkValue(fNodeName, fNodeName[nchunk][nindex], cchunk, cindex);
  506. setChunkValue(fNodeValue, fNodeValue[nchunk][nindex], cchunk, cindex);
  507. setChunkValue(fNodeURI, fNodeURI[nchunk][nindex], cchunk, cindex);
  508. int extraIndex = fNodeExtra[nchunk][nindex];
  509. if (extraIndex != -1) {
  510. if (nodeType != Node.ATTRIBUTE_NODE && nodeType != Node.TEXT_NODE) {
  511. extraIndex = cloneNode(extraIndex, false);
  512. }
  513. setChunkIndex(fNodeExtra, extraIndex, cchunk, cindex);
  514. }
  515. // clone and attach children
  516. if (deep) {
  517. int prevIndex = -1;
  518. int childIndex = getLastChild(nodeIndex, false);
  519. while (childIndex != -1) {
  520. int clonedChildIndex = cloneNode(childIndex, deep);
  521. insertBefore(cloneIndex, clonedChildIndex, prevIndex);
  522. prevIndex = clonedChildIndex;
  523. childIndex = getRealPrevSibling(childIndex, false);
  524. }
  525. }
  526. // return cloned node index
  527. return cloneIndex;
  528. } // cloneNode(int,boolean):int
  529. /** Appends a child to the specified parent in the table. */
  530. public void appendChild(int parentIndex, int childIndex) {
  531. // append parent index
  532. int pchunk = parentIndex >> CHUNK_SHIFT;
  533. int pindex = parentIndex & CHUNK_MASK;
  534. int cchunk = childIndex >> CHUNK_SHIFT;
  535. int cindex = childIndex & CHUNK_MASK;
  536. setChunkIndex(fNodeParent, parentIndex, cchunk, cindex);
  537. // set previous sibling of new child
  538. int olast = getChunkIndex(fNodeLastChild, pchunk, pindex);
  539. setChunkIndex(fNodePrevSib, olast, cchunk, cindex);
  540. // update parent's last child
  541. setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex);
  542. } // appendChild(int,int)
  543. /** Adds an attribute node to the specified element. */
  544. public int setAttributeNode(int elemIndex, int attrIndex) {
  545. int echunk = elemIndex >> CHUNK_SHIFT;
  546. int eindex = elemIndex & CHUNK_MASK;
  547. int achunk = attrIndex >> CHUNK_SHIFT;
  548. int aindex = attrIndex & CHUNK_MASK;
  549. // see if this attribute is already here
  550. String attrName = getChunkValue(fNodeName, achunk, aindex);
  551. int oldAttrIndex = getChunkIndex(fNodeExtra, echunk, eindex);
  552. int nextIndex = -1;
  553. int oachunk = -1;
  554. int oaindex = -1;
  555. while (oldAttrIndex != -1) {
  556. oachunk = oldAttrIndex >> CHUNK_SHIFT;
  557. oaindex = oldAttrIndex & CHUNK_MASK;
  558. String oldAttrName = getChunkValue(fNodeName, oachunk, oaindex);
  559. if (oldAttrName.equals(attrName)) {
  560. break;
  561. }
  562. nextIndex = oldAttrIndex;
  563. oldAttrIndex = getChunkIndex(fNodePrevSib, oachunk, oaindex);
  564. }
  565. // remove old attribute
  566. if (oldAttrIndex != -1) {
  567. // patch links
  568. int prevIndex = getChunkIndex(fNodePrevSib, oachunk, oaindex);
  569. if (nextIndex == -1) {
  570. setChunkIndex(fNodeExtra, prevIndex, echunk, eindex);
  571. }
  572. else {
  573. int pchunk = nextIndex >> CHUNK_SHIFT;
  574. int pindex = nextIndex & CHUNK_MASK;
  575. setChunkIndex(fNodePrevSib, prevIndex, pchunk, pindex);
  576. }
  577. // remove connections to siblings
  578. clearChunkIndex(fNodeType, oachunk, oaindex);
  579. clearChunkValue(fNodeName, oachunk, oaindex);
  580. clearChunkValue(fNodeValue, oachunk, oaindex);
  581. clearChunkIndex(fNodeParent, oachunk, oaindex);
  582. clearChunkIndex(fNodePrevSib, oachunk, oaindex);
  583. int attrTextIndex =
  584. clearChunkIndex(fNodeLastChild, oachunk, oaindex);
  585. int atchunk = attrTextIndex >> CHUNK_SHIFT;
  586. int atindex = attrTextIndex & CHUNK_MASK;
  587. clearChunkIndex(fNodeType, atchunk, atindex);
  588. clearChunkValue(fNodeValue, atchunk, atindex);
  589. clearChunkIndex(fNodeParent, atchunk, atindex);
  590. clearChunkIndex(fNodeLastChild, atchunk, atindex);
  591. }
  592. // add new attribute
  593. int prevIndex = getChunkIndex(fNodeExtra, echunk, eindex);
  594. setChunkIndex(fNodeExtra, attrIndex, echunk, eindex);
  595. setChunkIndex(fNodePrevSib, prevIndex, achunk, aindex);
  596. // return
  597. return oldAttrIndex;
  598. } // setAttributeNode(int,int):int
  599. /** Adds an attribute node to the specified element. */
  600. public void setIdAttributeNode(int elemIndex, int attrIndex) {
  601. int chunk = attrIndex >> CHUNK_SHIFT;
  602. int index = attrIndex & CHUNK_MASK;
  603. int extra = getChunkIndex(fNodeExtra, chunk, index);
  604. extra = extra | ID;
  605. setChunkIndex(fNodeExtra, extra, chunk, index);
  606. String value = getChunkValue(fNodeValue, chunk, index);
  607. putIdentifier(value, elemIndex);
  608. }
  609. /** Sets type of attribute */
  610. public void setIdAttribute(int attrIndex) {
  611. int chunk = attrIndex >> CHUNK_SHIFT;
  612. int index = attrIndex & CHUNK_MASK;
  613. int extra = getChunkIndex(fNodeExtra, chunk, index);
  614. extra = extra | ID;
  615. setChunkIndex(fNodeExtra, extra, chunk, index);
  616. }
  617. /** Inserts a child before the specified node in the table. */
  618. public int insertBefore(int parentIndex, int newChildIndex, int refChildIndex) {
  619. if (refChildIndex == -1) {
  620. appendChild(parentIndex, newChildIndex);
  621. return newChildIndex;
  622. }
  623. int nchunk = newChildIndex >> CHUNK_SHIFT;
  624. int nindex = newChildIndex & CHUNK_MASK;
  625. int rchunk = refChildIndex >> CHUNK_SHIFT;
  626. int rindex = refChildIndex & CHUNK_MASK;
  627. int previousIndex = getChunkIndex(fNodePrevSib, rchunk, rindex);
  628. setChunkIndex(fNodePrevSib, newChildIndex, rchunk, rindex);
  629. setChunkIndex(fNodePrevSib, previousIndex, nchunk, nindex);
  630. return newChildIndex;
  631. } // insertBefore(int,int,int):int
  632. /** Sets the last child of the parentIndex to childIndex. */
  633. public void setAsLastChild(int parentIndex, int childIndex) {
  634. int pchunk = parentIndex >> CHUNK_SHIFT;
  635. int pindex = parentIndex & CHUNK_MASK;
  636. int chunk = childIndex >> CHUNK_SHIFT;
  637. int index = childIndex & CHUNK_MASK;
  638. setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex);
  639. } // setAsLastChild(int,int)
  640. /**
  641. * Returns the parent node of the given node.
  642. * <em>Calling this method does not free the parent index.</em>
  643. */
  644. public int getParentNode(int nodeIndex) {
  645. return getParentNode(nodeIndex, false);
  646. }
  647. /**
  648. * Returns the parent node of the given node.
  649. * @param free True to free parent node.
  650. */
  651. public int getParentNode(int nodeIndex, boolean free) {
  652. if (nodeIndex == -1) {
  653. return -1;
  654. }
  655. int chunk = nodeIndex >> CHUNK_SHIFT;
  656. int index = nodeIndex & CHUNK_MASK;
  657. return free ? clearChunkIndex(fNodeParent, chunk, index)
  658. : getChunkIndex(fNodeParent, chunk, index);
  659. } // getParentNode(int):int
  660. /** Returns the last child of the given node. */
  661. public int getLastChild(int nodeIndex) {
  662. return getLastChild(nodeIndex, true);
  663. }
  664. /**
  665. * Returns the last child of the given node.
  666. * @param free True to free child index.
  667. */
  668. public int getLastChild(int nodeIndex, boolean free) {
  669. if (nodeIndex == -1) {
  670. return -1;
  671. }
  672. int chunk = nodeIndex >> CHUNK_SHIFT;
  673. int index = nodeIndex & CHUNK_MASK;
  674. return free ? clearChunkIndex(fNodeLastChild, chunk, index)
  675. : getChunkIndex(fNodeLastChild, chunk, index);
  676. } // getLastChild(int,boolean):int
  677. /**
  678. * Returns the prev sibling of the given node.
  679. * This is post-normalization of Text Nodes.
  680. */
  681. public int getPrevSibling(int nodeIndex) {
  682. return getPrevSibling(nodeIndex, true);
  683. }
  684. /**
  685. * Returns the prev sibling of the given node.
  686. * @param free True to free sibling index.
  687. */
  688. public int getPrevSibling(int nodeIndex, boolean free) {
  689. if (nodeIndex == -1) {
  690. return -1;
  691. }
  692. int chunk = nodeIndex >> CHUNK_SHIFT;
  693. int index = nodeIndex & CHUNK_MASK;
  694. int type = getChunkIndex(fNodeType, chunk, index);
  695. if (type == Node.TEXT_NODE) {
  696. do {
  697. nodeIndex = getChunkIndex(fNodePrevSib, chunk, index);
  698. if (nodeIndex == -1) {
  699. break;
  700. }
  701. chunk = nodeIndex >> CHUNK_SHIFT;
  702. index = nodeIndex & CHUNK_MASK;
  703. type = getChunkIndex(fNodeType, chunk, index);
  704. } while (type == Node.TEXT_NODE);
  705. }
  706. else {
  707. nodeIndex = getChunkIndex(fNodePrevSib, chunk, index);
  708. }
  709. return nodeIndex;
  710. } // getPrevSibling(int,boolean):int
  711. /**
  712. * Returns the <i>real</i> prev sibling of the given node,
  713. * directly from the data structures. Used by TextImpl#getNodeValue()
  714. * to normalize values.
  715. */
  716. public int getRealPrevSibling(int nodeIndex) {
  717. return getRealPrevSibling(nodeIndex, true);
  718. }
  719. /**
  720. * Returns the <i>real</i> prev sibling of the given node.
  721. * @param free True to free sibling index.
  722. */
  723. public int getRealPrevSibling(int nodeIndex, boolean free) {
  724. if (nodeIndex == -1) {
  725. return -1;
  726. }
  727. int chunk = nodeIndex >> CHUNK_SHIFT;
  728. int index = nodeIndex & CHUNK_MASK;
  729. return free ? clearChunkIndex(fNodePrevSib, chunk, index)
  730. : getChunkIndex(fNodePrevSib, chunk, index);
  731. } // getReadPrevSibling(int,boolean):int
  732. /**
  733. * Returns the index of the element definition in the table
  734. * with the specified name index, or -1 if no such definition
  735. * exists.
  736. */
  737. public int lookupElementDefinition(String elementName) {
  738. if (fNodeCount > 1) {
  739. // find doctype
  740. int docTypeIndex = -1;
  741. int nchunk = 0;
  742. int nindex = 0;
  743. for (int index = getChunkIndex(fNodeLastChild, nchunk, nindex);
  744. index != -1;
  745. index = getChunkIndex(fNodePrevSib, nchunk, nindex)) {
  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. // find element definition
  754. if (docTypeIndex == -1) {
  755. return -1;
  756. }
  757. nchunk = docTypeIndex >> CHUNK_SHIFT;
  758. nindex = docTypeIndex & CHUNK_MASK;
  759. for (int index = getChunkIndex(fNodeLastChild, nchunk, nindex);
  760. index != -1;
  761. index = getChunkIndex(fNodePrevSib, nchunk, nindex)) {
  762. nchunk = index >> CHUNK_SHIFT;
  763. nindex = index & CHUNK_MASK;
  764. if (getChunkIndex(fNodeType, nchunk, nindex) ==
  765. NodeImpl.ELEMENT_DEFINITION_NODE
  766. && getChunkValue(fNodeName, nchunk, nindex) == elementName) {
  767. return index;
  768. }
  769. }
  770. }
  771. return -1;
  772. } // lookupElementDefinition(String):int
  773. /** Instantiates the requested node object. */
  774. public DeferredNode getNodeObject(int nodeIndex) {
  775. // is there anything to do?
  776. if (nodeIndex == -1) {
  777. return null;
  778. }
  779. // get node type
  780. int chunk = nodeIndex >> CHUNK_SHIFT;
  781. int index = nodeIndex & CHUNK_MASK;
  782. int type = getChunkIndex(fNodeType, chunk, index);
  783. if (type != Node.TEXT_NODE && type != Node.CDATA_SECTION_NODE) {
  784. clearChunkIndex(fNodeType, chunk, index);
  785. }
  786. // create new node
  787. DeferredNode node = null;
  788. switch (type) {
  789. //
  790. // Standard DOM node types
  791. //
  792. case Node.ATTRIBUTE_NODE: {
  793. if (fNamespacesEnabled) {
  794. node = new DeferredAttrNSImpl(this, nodeIndex);
  795. } else {
  796. node = new DeferredAttrImpl(this, nodeIndex);
  797. }
  798. break;
  799. }
  800. case Node.CDATA_SECTION_NODE: {
  801. node = new DeferredCDATASectionImpl(this, nodeIndex);
  802. break;
  803. }
  804. case Node.COMMENT_NODE: {
  805. node = new DeferredCommentImpl(this, nodeIndex);
  806. break;
  807. }
  808. // NOTE: Document fragments can never be "fast".
  809. //
  810. // The parser will never ask to create a document
  811. // fragment during the parse. Document fragments
  812. // are used by the application *after* the parse.
  813. //
  814. // case Node.DOCUMENT_FRAGMENT_NODE: { break; }
  815. case Node.DOCUMENT_NODE: {
  816. // this node is never "fast"
  817. node = this;
  818. break;
  819. }
  820. case Node.DOCUMENT_TYPE_NODE: {
  821. node = new DeferredDocumentTypeImpl(this, nodeIndex);
  822. // save the doctype node
  823. docType = (DocumentTypeImpl)node;
  824. break;
  825. }
  826. case Node.ELEMENT_NODE: {
  827. if (DEBUG_IDS) {
  828. System.out.println("getNodeObject(ELEMENT_NODE): "+nodeIndex);
  829. }
  830. // create node
  831. if (fNamespacesEnabled) {
  832. node = new DeferredElementNSImpl(this, nodeIndex);
  833. } else {
  834. node = new DeferredElementImpl(this, nodeIndex);
  835. }
  836. // save the document element node
  837. if (docElement == null) {
  838. docElement = (ElementImpl)node;
  839. }
  840. // check to see if this element needs to be
  841. // registered for its ID attributes
  842. if (fIdElement != null) {
  843. int idIndex = binarySearch(fIdElement, 0,
  844. fIdCount-1, nodeIndex);
  845. while (idIndex != -1) {
  846. if (DEBUG_IDS) {
  847. System.out.println(" id index: "+idIndex);
  848. System.out.println(" fIdName["+idIndex+
  849. "]: "+fIdName[idIndex]);
  850. }
  851. // register ID
  852. String name = fIdName[idIndex];
  853. if (name != null) {
  854. if (DEBUG_IDS) {
  855. System.out.println(" name: "+name);
  856. System.out.print("getNodeObject()#");
  857. }
  858. putIdentifier0(name, (Element)node);
  859. fIdName[idIndex] = null;
  860. }
  861. // continue if there are more IDs for
  862. // this element
  863. if (idIndex + 1 < fIdCount &&
  864. fIdElement[idIndex + 1] == nodeIndex) {
  865. idIndex++;
  866. }
  867. else {
  868. idIndex = -1;
  869. }
  870. }
  871. }
  872. break;
  873. }
  874. case Node.ENTITY_NODE: {
  875. node = new DeferredEntityImpl(this, nodeIndex);
  876. break;
  877. }
  878. case Node.ENTITY_REFERENCE_NODE: {
  879. node = new DeferredEntityReferenceImpl(this, nodeIndex);
  880. break;
  881. }
  882. case Node.NOTATION_NODE: {
  883. node = new DeferredNotationImpl(this, nodeIndex);
  884. break;
  885. }
  886. case Node.PROCESSING_INSTRUCTION_NODE: {
  887. node = new DeferredProcessingInstructionImpl(this, nodeIndex);
  888. break;
  889. }
  890. case Node.TEXT_NODE: {
  891. node = new DeferredTextImpl(this, nodeIndex);
  892. break;
  893. }
  894. //
  895. // non-standard DOM node types
  896. //
  897. case NodeImpl.ELEMENT_DEFINITION_NODE: {
  898. node = new DeferredElementDefinitionImpl(this, nodeIndex);
  899. break;
  900. }
  901. default: {
  902. throw new IllegalArgumentException("type: "+type);
  903. }
  904. } // switch node type
  905. // store and return
  906. if (node != null) {
  907. return node;
  908. }
  909. // error
  910. throw new IllegalArgumentException();
  911. } // createNodeObject(int):Node
  912. /** Returns the name of the given node. */
  913. public String getNodeName(int nodeIndex) {
  914. return getNodeName(nodeIndex, true);
  915. } // getNodeNameString(int):String
  916. /**
  917. * Returns the name of the given node.
  918. * @param free True to free the string index.
  919. */
  920. public String getNodeName(int nodeIndex, boolean free) {
  921. if (nodeIndex == -1) {
  922. return null;
  923. }
  924. int chunk = nodeIndex >> CHUNK_SHIFT;
  925. int index = nodeIndex & CHUNK_MASK;
  926. return free ? clearChunkValue(fNodeName, chunk, index)
  927. : getChunkValue(fNodeName, chunk, index);
  928. } // getNodeName(int,boolean):String
  929. /** Returns the real value of the given node. */
  930. public String getNodeValueString(int nodeIndex) {
  931. return getNodeValueString(nodeIndex, true);
  932. } // getNodeValueString(int):String
  933. /**
  934. * Returns the real value of the given node.
  935. * @param free True to free the string index.
  936. */
  937. public String getNodeValueString(int nodeIndex, boolean free) {
  938. if (nodeIndex == -1) {
  939. return null;
  940. }
  941. int chunk = nodeIndex >> CHUNK_SHIFT;
  942. int index = nodeIndex & CHUNK_MASK;
  943. String value = free ? clearChunkValue(fNodeValue, chunk, index)
  944. : getChunkValue(fNodeValue, chunk, index);
  945. if (value == null) {
  946. return null;
  947. }
  948. int type = getChunkIndex(fNodeType, chunk, index);
  949. if (type == Node.TEXT_NODE) {
  950. int prevSib = getRealPrevSibling(nodeIndex);
  951. if (prevSib != -1 &&
  952. getNodeType(prevSib, false) == Node.TEXT_NODE) {
  953. // append data that is stored in fNodeValue
  954. // REVISIT: for text nodes it works differently than for CDATA
  955. // nodes.
  956. fStrChunks.addElement(value);
  957. do {
  958. // go in reverse order: find last child, then
  959. // its previous sibling, etc
  960. chunk = prevSib >> CHUNK_SHIFT;
  961. index = prevSib & CHUNK_MASK;
  962. value = getChunkValue(fNodeValue, chunk, index);
  963. fStrChunks.addElement(value);
  964. prevSib = getChunkIndex(fNodePrevSib, chunk, index);
  965. if (prevSib == -1) {
  966. break;
  967. }
  968. } while (getNodeType(prevSib, false) == Node.TEXT_NODE);
  969. int chunkCount = fStrChunks.size();
  970. // add to the buffer in the correct order.
  971. for (int i = chunkCount - 1; i >= 0; i--) {
  972. fBufferStr.append((String)fStrChunks.elementAt(i));
  973. }
  974. value = fBufferStr.toString();
  975. fStrChunks.removeAllElements();
  976. fBufferStr.setLength(0);
  977. return value;
  978. }
  979. }
  980. else if (type == Node.CDATA_SECTION_NODE) {
  981. // find if any other data stored in children
  982. int child = getLastChild(nodeIndex, false);
  983. if (child !=-1) {
  984. // append data that is stored in fNodeValue
  985. fBufferStr.append(value);
  986. while (child !=-1) {
  987. // go in reverse order: find last child, then
  988. // its previous sibling, etc
  989. chunk = child >> CHUNK_SHIFT;
  990. index = child & CHUNK_MASK;
  991. value = getChunkValue(fNodeValue, chunk, index);
  992. fStrChunks.addElement(value);
  993. child = getChunkIndex(fNodePrevSib, chunk, index);
  994. }
  995. // add to the buffer in the correct order.
  996. for (int i=fStrChunks.size()-1; i>=0; i--) {
  997. fBufferStr.append((String)fStrChunks.elementAt(i));
  998. }
  999. value = fBufferStr.toString();
  1000. fStrChunks.setSize(0);
  1001. fBufferStr.setLength(0);
  1002. return value;
  1003. }
  1004. }
  1005. return value;
  1006. } // getNodeValueString(int,boolean):String
  1007. /**
  1008. * Returns the value of the given node.
  1009. */
  1010. public String getNodeValue(int nodeIndex) {
  1011. return getNodeValue(nodeIndex, true);
  1012. }
  1013. /**
  1014. * Clears the type info that is stored in the fNodeValue array
  1015. * @param nodeIndex
  1016. * @return Object - type information for the attribute/element node
  1017. */
  1018. public TypeInfo getTypeInfo(int nodeIndex) {
  1019. if (nodeIndex == -1) {
  1020. return null;
  1021. }
  1022. int chunk = nodeIndex >> CHUNK_SHIFT;
  1023. int index = nodeIndex & CHUNK_MASK;
  1024. TypeInfo value = (TypeInfo)(fNodeValue[chunk] != null ? fNodeValue[chunk][index] : null);
  1025. if (value != null) {
  1026. fNodeValue[chunk][index] = null;
  1027. RefCount c = (RefCount) fNodeValue[chunk][CHUNK_SIZE];
  1028. c.fCount--;
  1029. if (c.fCount == 0) {
  1030. fNodeValue[chunk] = null;
  1031. }
  1032. }
  1033. return value;
  1034. }
  1035. /**
  1036. * Returns the value of the given node.
  1037. * @param free True to free the value index.
  1038. */
  1039. public String getNodeValue(int nodeIndex, boolean free) {
  1040. if (nodeIndex == -1) {
  1041. return null;
  1042. }
  1043. int chunk = nodeIndex >> CHUNK_SHIFT;
  1044. int index = nodeIndex & CHUNK_MASK;
  1045. return free ? clearChunkValue(fNodeValue, chunk, index)
  1046. : getChunkValue(fNodeValue, chunk, index);
  1047. } // getNodeValue(int,boolean):String
  1048. /**
  1049. * Returns the extra info of the given node.
  1050. * Used by AttrImpl to store specified value (1 == true).
  1051. */
  1052. public int getNodeExtra(int nodeIndex) {
  1053. return getNodeExtra(nodeIndex, true);
  1054. }
  1055. /**
  1056. * Returns the extra info of the given node.
  1057. * @param free True to free the value index.
  1058. */
  1059. public int getNodeExtra(int nodeIndex, boolean free) {
  1060. if (nodeIndex == -1) {
  1061. return -1;
  1062. }
  1063. int chunk = nodeIndex >> CHUNK_SHIFT;
  1064. int index = nodeIndex & CHUNK_MASK;
  1065. return free ? clearChunkIndex(fNodeExtra, chunk, index)
  1066. : getChunkIndex(fNodeExtra, chunk, index);
  1067. } // getNodeExtra(int,boolean):int
  1068. /** Returns the type of the given node. */
  1069. public short getNodeType(int nodeIndex) {
  1070. return getNodeType(nodeIndex, true);
  1071. }
  1072. /**
  1073. * Returns the type of the given node.
  1074. * @param free True to free type index.
  1075. */
  1076. public short getNodeType(int nodeIndex, boolean free) {
  1077. if (nodeIndex == -1) {
  1078. return -1;
  1079. }
  1080. int chunk = nodeIndex >> CHUNK_SHIFT;
  1081. int index = nodeIndex & CHUNK_MASK;
  1082. return free ? (short)clearChunkIndex(fNodeType, chunk, index)
  1083. : (short)getChunkIndex(fNodeType, chunk, index);
  1084. } // getNodeType(int):int
  1085. /** Returns the attribute value of the given name. */
  1086. public String getAttribute(int elemIndex, String name) {
  1087. if (elemIndex == -1 || name == null) {
  1088. return null;
  1089. }
  1090. int echunk = elemIndex >> CHUNK_SHIFT;
  1091. int eindex = elemIndex & CHUNK_MASK;
  1092. int attrIndex = getChunkIndex(fNodeExtra, echunk, eindex);
  1093. while (attrIndex != -1) {
  1094. int achunk = attrIndex >> CHUNK_SHIFT;
  1095. int aindex = attrIndex & CHUNK_MASK;
  1096. if (getChunkValue(fNodeName, achunk, aindex) == name) {
  1097. return getChunkValue(fNodeValue, achunk, aindex);
  1098. }
  1099. attrIndex = getChunkIndex(fNodePrevSib, achunk, aindex);
  1100. }
  1101. return null;
  1102. }
  1103. /** Returns the URI of the given node. */
  1104. public String getNodeURI(int nodeIndex) {
  1105. return getNodeURI(nodeIndex, true);
  1106. }
  1107. /**
  1108. * Returns the URI of the given node.
  1109. * @param free True to free URI index.
  1110. */
  1111. public String getNodeURI(int nodeIndex, boolean free) {
  1112. if (nodeIndex == -1) {
  1113. return null;
  1114. }
  1115. int chunk = nodeIndex >> CHUNK_SHIFT;
  1116. int index = nodeIndex & CHUNK_MASK;
  1117. return free ? clearChunkValue(fNodeURI, chunk, index)
  1118. : getChunkValue(fNodeURI, chunk, index);
  1119. } // getNodeURI(int,int):String
  1120. // identifier maintenance
  1121. /** Registers an identifier name with a specified element node. */
  1122. public void putIdentifier(String name, int elementNodeIndex) {
  1123. if (DEBUG_IDS) {
  1124. System.out.println("putIdentifier(" + name + ", "
  1125. + elementNodeIndex + ')' + " // " +
  1126. getChunkValue(fNodeName,
  1127. elementNodeIndex >> CHUNK_SHIFT,
  1128. elementNodeIndex & CHUNK_MASK));
  1129. }
  1130. // initialize arrays
  1131. if (fIdName == null) {
  1132. fIdName = new String[64];
  1133. fIdElement = new int[64];
  1134. }
  1135. // resize arrays
  1136. if (fIdCount == fIdName.length) {
  1137. String idName[] = new String[fIdCount * 2];
  1138. System.arraycopy(fIdName, 0, idName, 0, fIdCount);
  1139. fIdName = idName;
  1140. int idElement[] = new int[idName.length];
  1141. System.arraycopy(fIdElement, 0, idElement, 0, fIdCount);
  1142. fIdElement = idElement;
  1143. }
  1144. // store identifier
  1145. fIdName[fIdCount] = name;
  1146. fIdElement[fIdCount] = elementNodeIndex;
  1147. fIdCount++;
  1148. } // putIdentifier(String,int)
  1149. //
  1150. // DEBUG
  1151. //
  1152. /** Prints out the tables. */
  1153. public void print() {
  1154. if (DEBUG_PRINT_REF_COUNTS) {
  1155. System.out.print("num\t");
  1156. System.out.print("type\t");
  1157. System.out.print("name\t");
  1158. System.out.print("val\t");
  1159. System.out.print("par\t");
  1160. System.out.print("lch\t");
  1161. System.out.print("psib");
  1162. System.out.println();
  1163. for (int i = 0; i < fNodeType.length; i++) {
  1164. if (fNodeType[i] != null) {
  1165. // separator
  1166. System.out.print("--------");
  1167. System.out.print("--------");
  1168. System.out.print("--------");
  1169. System.out.print("--------");
  1170. System.out.print("--------");
  1171. System.out.print("--------");
  1172. System.out.print("--------");
  1173. System.out.println();
  1174. // ref count
  1175. System.out.print(i);
  1176. System.out.print('\t');
  1177. switch (fNodeType[i][CHUNK_SIZE]) {
  1178. case DocumentImpl.ELEMENT_DEFINITION_NODE: { System.out.print("EDef"); break; }
  1179. case Node.DOCUMENT_NODE: { System.out.print("Doc"); break; }
  1180. case Node.DOCUMENT_TYPE_NODE: { System.out.print("DType"); break; }
  1181. case Node.COMMENT_NODE: { System.out.print("Com"); break; }
  1182. case Node.PROCESSING_INSTRUCTION_NODE: { System.out.print("PI"); break; }
  1183. case Node.ELEMENT_NODE: { System.out.print("Elem"); break; }
  1184. case Node.ENTITY_NODE: { System.out.print("Ent"); break; }
  1185. case Node.ENTITY_REFERENCE_NODE: { System.out.print("ERef"); break; }
  1186. case Node.TEXT_NODE: { System.out.print("Text"); break; }
  1187. case Node.ATTRIBUTE_NODE: { System.out.print("Attr"); break; }
  1188. case DeferredNode.TYPE_NODE: { System.out.print("TypeInfo"); break; }
  1189. default: { System.out.print("?"+fNodeType[i][CHUNK_SIZE]); }
  1190. }
  1191. System.out.print('\t');
  1192. System.out.print(fNodeName[i][CHUNK_SIZE]);
  1193. System.out.print('\t');
  1194. System.out.print(fNodeValue[i][CHUNK_SIZE]);
  1195. System.out.print('\t');
  1196. System.out.print(fNodeURI[i][CHUNK_SIZE]);
  1197. System.out.print('\t');
  1198. System.out.print(fNodeParent[i][CHUNK_SIZE]);
  1199. System.out.print('\t');
  1200. System.out.print(fNodeLastChild[i][CHUNK_SIZE]);
  1201. System.out.print('\t');
  1202. System.out.print(fNodePrevSib[i][CHUNK_SIZE]);
  1203. System.out.print('\t');
  1204. System.out.print(fNodeExtra[i][CHUNK_SIZE]);
  1205. System.out.println();
  1206. }
  1207. }
  1208. }
  1209. if (DEBUG_PRINT_TABLES) {
  1210. // This assumes that the document is small
  1211. System.out.println("# start table");
  1212. for (int i = 0; i < fNodeCount; i++) {
  1213. int chunk = i >> CHUNK_SHIFT;
  1214. int index = i & CHUNK_MASK;
  1215. if (i % 10 == 0) {
  1216. System.out.print("num\t");
  1217. System.out.print("type\t");
  1218. System.out.print("name\t");
  1219. System.out.print("val\t");
  1220. System.out.print("uri\t");
  1221. System.out.print("par\t");
  1222. System.out.print("lch\t");
  1223. System.out.print("psib\t");
  1224. System.out.print("xtra");
  1225. System.out.println();
  1226. }
  1227. System.out.print(i);
  1228. System.out.print('\t');
  1229. switch (getChunkIndex(fNodeType, chunk, index)) {
  1230. case DocumentImpl.ELEMENT_DEFINITION_NODE: { System.out.print("EDef"); break; }
  1231. case Node.DOCUMENT_NODE: { System.out.print("Doc"); break; }
  1232. case Node.DOCUMENT_TYPE_NODE: { System.out.print("DType"); break; }
  1233. case Node.COMMENT_NODE: { System.out.print("Com"); break; }
  1234. case Node.PROCESSING_INSTRUCTION_NODE: { System.out.print("PI"); break; }
  1235. case Node.ELEMENT_NODE: { System.out.print("Elem"); break; }
  1236. case Node.ENTITY_NODE: { System.out.print("Ent"); break; }
  1237. case Node.ENTITY_REFERENCE_NODE: { System.out.print("ERef"); break; }
  1238. case Node.TEXT_NODE: { System.out.print("Text"); break; }
  1239. case Node.ATTRIBUTE_NODE: { System.out.print("Attr"); break; }
  1240. case DeferredNode.TYPE_NODE: { System.out.print("TypeInfo"); break; }
  1241. default: { System.out.print("?"+getChunkIndex(fNodeType, chunk, index)); }
  1242. }
  1243. System.out.print('\t');
  1244. System.out.print(getChunkValue(fNodeName, chunk, index));
  1245. System.out.print('\t');
  1246. System.out.print(getNodeValue(chunk, index));
  1247. System.out.print('\t');
  1248. System.out.print(getChunkValue(fNodeURI, chunk, index));
  1249. System.out.print('\t');
  1250. System.out.print(getChunkIndex(fNodeParent, chunk, index));
  1251. System.out.print('\t');
  1252. System.out.print(getChunkIndex(fNodeLastChild, chunk, index));
  1253. System.out.print('\t');
  1254. System.out.print(getChunkIndex(fNodePrevSib, chunk, index));
  1255. System.out.print('\t');
  1256. System.out.print(getChunkIndex(fNodeExtra, chunk, index));
  1257. System.out.println();
  1258. }
  1259. System.out.println("# end table");
  1260. }
  1261. } // print()
  1262. //
  1263. // DeferredNode methods
  1264. //
  1265. /** Returns the node index. */
  1266. public int getNodeIndex() {
  1267. return 0;
  1268. }
  1269. //
  1270. // Protected methods
  1271. //
  1272. /** Synchronizes the node's data. */
  1273. protected void synchronizeData() {
  1274. // no need to sync in the future
  1275. needsSyncData(false);
  1276. // fluff up enough nodes to fill identifiers hash
  1277. if (fIdElement != null) {
  1278. // REVISIT: There has to be a more efficient way of
  1279. // doing this. But keep in mind that the
  1280. // tree can have been altered and re-ordered
  1281. // before all of the element nodes with ID
  1282. // attributes have been registered. For now
  1283. // this is reasonable and safe. -Ac
  1284. IntVector path = new IntVector();
  1285. for (int i = 0; i < fIdCount; i++) {
  1286. // ignore if it's already been registered
  1287. int elementNodeIndex = fIdElement[i];
  1288. String idName = fIdName[i];
  1289. if (idName == null) {
  1290. continue;
  1291. }
  1292. // find path from this element to the root
  1293. path.removeAllElements();
  1294. int index = elementNodeIndex;
  1295. do {
  1296. path.addElement(index);
  1297. int pchunk = index >> CHUNK_SHIFT;
  1298. int pindex = index & CHUNK_MASK;
  1299. index = getChunkIndex(fNodeParent, pchunk, pindex);
  1300. } while (index != -1);
  1301. // Traverse path (backwards), fluffing the elements
  1302. // along the way. When this loop finishes, "place"
  1303. // will contain the reference to the element node
  1304. // we're interested in. -Ac
  1305. Node place = this;
  1306. for (int j = path.size() - 2; j >= 0; j--) {
  1307. index = path.elementAt(j);
  1308. Node child = place.getLastChild();
  1309. while (child != null) {
  1310. if (child instanceof DeferredNode) {
  1311. int nodeIndex =
  1312. ((DeferredNode)child).getNodeIndex();
  1313. if (nodeIndex == index) {
  1314. place = child;
  1315. break;
  1316. }
  1317. }
  1318. child = child.getPreviousSibling();
  1319. }
  1320. }
  1321. // register the element
  1322. Element element = (Element)place;
  1323. putIdentifier0(idName, element);
  1324. fIdName[i] = null;
  1325. // see if there are more IDs on this element
  1326. while (i + 1 < fIdCount &&
  1327. fIdElement[i + 1] == elementNodeIndex) {
  1328. idName = fIdName[++i];
  1329. if (idName == null) {
  1330. continue;
  1331. }
  1332. putIdentifier0(idName, element);
  1333. }
  1334. }
  1335. } // if identifiers
  1336. } // synchronizeData()
  1337. /**
  1338. * Synchronizes the node's children with the internal structure.
  1339. * Fluffing the children at once solves a lot of work to keep
  1340. * the two structures in sync. The problem gets worse when
  1341. * editing the tree -- this makes it a lot easier.
  1342. */
  1343. protected void synchronizeChildren() {
  1344. if (needsSyncData()) {
  1345. synchronizeData();
  1346. /*
  1347. * when we have elements with IDs this method is being recursively
  1348. * called from synchronizeData, in which case we've already gone
  1349. * through the following and we can now simply stop here.
  1350. */
  1351. if (!needsSyncChildren()) {
  1352. return;
  1353. }
  1354. }
  1355. // we don't want to generate any event for this so turn them off
  1356. boolean orig = mutationEvents;
  1357. mutationEvents = false;
  1358. // no need to sync in the future
  1359. needsSyncChildren(false);
  1360. getNodeType(0);
  1361. // create children and link them as siblings
  1362. ChildNode first = null;
  1363. ChildNode last = null;
  1364. for (int index = getLastChild(0);
  1365. index != -1;
  1366. index = getPrevSibling(index)) {
  1367. ChildNode node = (ChildNode)getNodeObject(index);
  1368. if (last == null) {
  1369. last = node;
  1370. }
  1371. else {
  1372. first.previousSibling = node;
  1373. }
  1374. node.ownerNode = this;
  1375. node.isOwned(true);
  1376. node.nextSibling = first;
  1377. first = node;
  1378. // save doctype and document type
  1379. int type = node.getNodeType();
  1380. if (type == Node.ELEMENT_NODE) {
  1381. docElement = (ElementImpl)node;
  1382. }
  1383. else if (type == Node.DOCUMENT_TYPE_NODE) {
  1384. docType = (DocumentTypeImpl)node;
  1385. }
  1386. }
  1387. if (first != null) {
  1388. firstChild = first;
  1389. first.isFirstChild(true);
  1390. lastChild(last);
  1391. }
  1392. // set mutation events flag back to its original value
  1393. mutationEvents = orig;
  1394. } // synchronizeChildren()
  1395. /**
  1396. * Synchronizes the node's children with the internal structure.
  1397. * Fluffing the children at once solves a lot of work to keep
  1398. * the two structures in sync. The problem gets worse when
  1399. * editing the tree -- this makes it a lot easier.
  1400. * This is not directly used in this class but this method is
  1401. * here so that it can be shared by all deferred subclasses of AttrImpl.
  1402. */
  1403. protected final void synchronizeChildren(AttrImpl a, int nodeIndex) {
  1404. // we don't want to generate any event for this so turn them off
  1405. boolean orig = getMutationEvents();
  1406. setMutationEvents(false);
  1407. // no need to sync in the future
  1408. a.needsSyncChildren(false);
  1409. // create children and link them as siblings or simply store the value
  1410. // as a String if all we have is one piece of text
  1411. int last = getLastChild(nodeIndex);
  1412. int prev = getPrevSibling(last);
  1413. if (prev == -1) {
  1414. a.value = getNodeValueString(nodeIndex);
  1415. a.hasStringValue(true);
  1416. }
  1417. else {
  1418. ChildNode firstNode = null;
  1419. ChildNode lastNode = null;
  1420. for (int index = last; index != -1;
  1421. index = getPrevSibling(index)) {
  1422. ChildNode node = (ChildNode) getNodeObject(index);
  1423. if (lastNode == null) {
  1424. lastNode = node;
  1425. }
  1426. else {
  1427. firstNode.previousSibling = node;
  1428. }
  1429. node.ownerNode = a;
  1430. node.isOwned(true);
  1431. node.nextSibling = firstNode;
  1432. firstNode = node;
  1433. }
  1434. if (lastNode != null) {
  1435. a.value = firstNode; // firstChild = firstNode
  1436. firstNode.isFirstChild(true);
  1437. a.lastChild(lastNode);
  1438. }
  1439. a.hasStringValue(false);
  1440. }
  1441. // set mutation events flag back to its original value
  1442. setMutationEvents(orig);
  1443. } // synchronizeChildren(AttrImpl,int):void
  1444. /**
  1445. * Synchronizes the node's children with the internal structure.
  1446. * Fluffing the children at once solves a lot of work to keep
  1447. * the two structures in sync. The problem gets worse when
  1448. * editing the tree -- this makes it a lot easier.
  1449. * This is not directly used in this class but this method is
  1450. * here so that it can be shared by all deferred subclasses of ParentNode.
  1451. */
  1452. protected final void synchronizeChildren(ParentNode p, int nodeIndex) {
  1453. // we don't want to generate any event for this so turn them off
  1454. boolean orig = getMutationEvents();
  1455. setMutationEvents(false);
  1456. // no need to sync in the future
  1457. p.needsSyncChildren(false);
  1458. // create children and link them as siblings
  1459. ChildNode firstNode = null;
  1460. ChildNode lastNode = null;
  1461. for (int index = getLastChild(nodeIndex);
  1462. index != -1;
  1463. index = getPrevSibling(index)) {
  1464. ChildNode node = (ChildNode) getNodeObject(index);
  1465. if (lastNode == null) {
  1466. lastNode = node;
  1467. }
  1468. else {
  1469. firstNode.previousSibling = node;
  1470. }
  1471. node.ownerNode = p;
  1472. node.isOwned(true);
  1473. node.nextSibling = firstNode;
  1474. firstNode = node;
  1475. }
  1476. if (lastNode != null) {
  1477. p.firstChild = firstNode;
  1478. firstNode.isFirstChild(true);
  1479. p.lastChild(lastNode);
  1480. }
  1481. // set mutation events flag back to its original value
  1482. setMutationEvents(orig);
  1483. } // synchronizeChildren(ParentNode,int):void
  1484. // utility methods
  1485. /** Ensures that the internal tables are large enough. */
  1486. protected void ensureCapacity(int chunk) {
  1487. if (fNodeType == null) {
  1488. // create buffers
  1489. fNodeType = new int[INITIAL_CHUNK_COUNT][];
  1490. fNodeName = new Object[INITIAL_CHUNK_COUNT][];
  1491. fNodeValue = new Object[INITIAL_CHUNK_COUNT][];
  1492. fNodeParent = new int[INITIAL_CHUNK_COUNT][];
  1493. fNodeLastChild = new int[INITIAL_CHUNK_COUNT][];
  1494. fNodePrevSib = new int[INITIAL_CHUNK_COUNT][];
  1495. fNodeURI = new Object[INITIAL_CHUNK_COUNT][];
  1496. fNodeExtra = new int[INITIAL_CHUNK_COUNT][];
  1497. }
  1498. else if (fNodeType.length <= chunk) {
  1499. // resize the tables
  1500. int newsize = chunk * 2;
  1501. int[][] newArray = new int[newsize][];
  1502. System.arraycopy(fNodeType, 0, newArray, 0, chunk);
  1503. fNodeType = newArray;
  1504. Object[][] newStrArray = new Object[newsize][];
  1505. System.arraycopy(fNodeName, 0, newStrArray, 0, chunk);
  1506. fNodeName = newStrArray;
  1507. newStrArray = new Object[newsize][];
  1508. System.arraycopy(fNodeValue, 0, newStrArray, 0, chunk);
  1509. fNodeValue = newStrArray;
  1510. newArray = new int[newsize][];
  1511. System.arraycopy(fNodeParent, 0, newArray, 0, chunk);
  1512. fNodeParent = newArray;
  1513. newArray = new int[newsize][];
  1514. System.arraycopy(fNodeLastChild, 0, newArray, 0, chunk);
  1515. fNodeLastChild = newArray;
  1516. newArray = new int[newsize][];
  1517. System.arraycopy(fNodePrevSib, 0, newArray, 0, chunk);
  1518. fNodePrevSib = newArray;
  1519. newStrArray = new Object[newsize][];
  1520. System.arraycopy(fNodeURI, 0, newStrArray, 0, chunk);
  1521. fNodeURI = newStrArray;
  1522. newArray = new int[newsize][];
  1523. System.arraycopy(fNodeExtra, 0, newArray, 0, chunk);
  1524. fNodeExtra = newArray;
  1525. }
  1526. else if (fNodeType[chunk] != null) {
  1527. // Done - there's sufficient capacity
  1528. return;
  1529. }
  1530. // create new chunks
  1531. createChunk(fNodeType, chunk);
  1532. createChunk(fNodeName, chunk);
  1533. createChunk(fNodeValue, chunk);
  1534. createChunk(fNodeParent, chunk);
  1535. createChunk(fNodeLastChild, chunk);
  1536. createChunk(fNodePrevSib, chunk);
  1537. createChunk(fNodeURI, chunk);
  1538. createChunk(fNodeExtra, chunk);
  1539. // Done
  1540. return;
  1541. } // ensureCapacity(int,int)
  1542. /** Creates a node of the specified type. */
  1543. protected int createNode(short nodeType) {
  1544. // ensure tables are large enough
  1545. int chunk = fNodeCount >> CHUNK_SHIFT;
  1546. int index = fNodeCount & CHUNK_MASK;
  1547. ensureCapacity(chunk);
  1548. // initialize node
  1549. setChunkIndex(fNodeType, nodeType, chunk, index);
  1550. // return node index number
  1551. return fNodeCount++;
  1552. } // createNode(short):int
  1553. /**
  1554. * Performs a binary search for a target value in an array of
  1555. * values. The array of values must be in ascending sorted order
  1556. * before calling this method and all array values must be
  1557. * non-negative.
  1558. *
  1559. * @param values The array of values to search.
  1560. * @param start The starting offset of the search.
  1561. * @param end The ending offset of the search.
  1562. * @param target The target value.
  1563. *
  1564. * @return This function will return the <i>first</i> occurrence
  1565. * of the target value, or -1 if the target value cannot
  1566. * be found.
  1567. */
  1568. protected static int binarySearch(final int values[],
  1569. int start, int end, int target) {
  1570. if (DEBUG_IDS) {
  1571. System.out.println("binarySearch(), target: "+target);
  1572. }
  1573. // look for target value
  1574. while (start <= end) {
  1575. // is this the one we're looking for?
  1576. int middle = (start + end) / 2;
  1577. int value = values[middle];
  1578. if (DEBUG_IDS) {
  1579. System.out.print(" value: "+value+", target: "+target+" // ");
  1580. print(values, start, end, middle, target);
  1581. }
  1582. if (value == target) {
  1583. while (middle > 0 && values[middle - 1] == target) {
  1584. middle--;
  1585. }
  1586. if (DEBUG_IDS) {
  1587. System.out.println("FOUND AT "+middle);
  1588. }
  1589. return middle;
  1590. }
  1591. // is this point higher or lower?
  1592. if (value > target) {
  1593. end = middle - 1;
  1594. }
  1595. else {
  1596. start = middle + 1;
  1597. }
  1598. } // while
  1599. // not found
  1600. if (DEBUG_IDS) {
  1601. System.out.println("NOT FOUND!");
  1602. }
  1603. return -1;
  1604. } // binarySearch(int[],int,int,int):int
  1605. //
  1606. // Private methods
  1607. //
  1608. private static final int[] INIT_ARRAY = new int[CHUNK_SIZE + 1];
  1609. static {
  1610. for (int i = 0; i < CHUNK_SIZE; i++) {
  1611. INIT_ARRAY[i] = -1;
  1612. }
  1613. }
  1614. /** Creates the specified chunk in the given array of chunks. */
  1615. private final void createChunk(int data[][], int chunk) {
  1616. data[chunk] = new int[CHUNK_SIZE + 1];
  1617. System.arraycopy(INIT_ARRAY, 0, data[chunk], 0, CHUNK_SIZE);
  1618. }
  1619. class RefCount {
  1620. int fCount;
  1621. }
  1622. private final void createChunk(Object data[][], int chunk) {
  1623. data[chunk] = new Object[CHUNK_SIZE + 1];
  1624. data[chunk][CHUNK_SIZE] = new RefCount();
  1625. }
  1626. /**
  1627. * Sets the specified value in the given of data at the chunk and index.
  1628. *
  1629. * @return Returns the old value.
  1630. */
  1631. private final int setChunkIndex(int data[][], int value,
  1632. int chunk, int index) {
  1633. if (value == -1) {
  1634. return clearChunkIndex(data, chunk, index);
  1635. }
  1636. int ovalue = data[chunk][index];
  1637. if (ovalue == -1) {
  1638. data[chunk][CHUNK_SIZE]++;
  1639. }
  1640. data[chunk][index] = value;
  1641. return ovalue;
  1642. }
  1643. private final String setChunkValue(Object data[][], Object value,
  1644. int chunk, int index) {
  1645. if (value == null) {
  1646. return clearChunkValue(data, chunk, index);
  1647. }
  1648. String ovalue = (String) data[chunk][index];
  1649. if (ovalue == null) {
  1650. RefCount c = (RefCount) data[chunk][CHUNK_SIZE];
  1651. c.fCount++;
  1652. }
  1653. data[chunk][index] = value;
  1654. return ovalue;
  1655. }
  1656. /**
  1657. * Returns the specified value in the given data at the chunk and index.
  1658. */
  1659. private final int getChunkIndex(int data[][], int chunk, int index) {
  1660. return data[chunk] != null ? data[chunk][index] : -1;
  1661. }
  1662. private final String getChunkValue(Object data[][], int chunk, int index) {
  1663. return data[chunk] != null ? (String) data[chunk][index] : null;
  1664. }
  1665. private final String getNodeValue(int chunk, int index) {
  1666. Object data = fNodeValue[chunk][index];
  1667. if (data == null){
  1668. return null;
  1669. }
  1670. else if (data instanceof String){
  1671. return (String)data;
  1672. }
  1673. else {
  1674. // type information
  1675. return data.toString();
  1676. }
  1677. }
  1678. /**
  1679. * Clears the specified value in the given data at the chunk and index.
  1680. * Note that this method will clear the given chunk if the reference
  1681. * count becomes zero.
  1682. *
  1683. * @return Returns the old value.
  1684. */
  1685. private final int clearChunkIndex(int data[][], int chunk, int index) {
  1686. int value = data[chunk] != null ? data[chunk][index] : -1;
  1687. if (value != -1) {
  1688. data[chunk][CHUNK_SIZE]--;
  1689. data[chunk][index] = -1;
  1690. if (data[chunk][CHUNK_SIZE] == 0) {
  1691. data[chunk] = null;
  1692. }
  1693. }
  1694. return value;
  1695. }
  1696. private final String clearChunkValue(Object data[][],
  1697. int chunk, int index) {
  1698. String value = data[chunk] != null ? (String)data[chunk][index] : null;
  1699. if (value != null) {
  1700. data[chunk][index] = null;
  1701. RefCount c = (RefCount) data[chunk][CHUNK_SIZE];
  1702. c.fCount--;
  1703. if (c.fCount == 0) {
  1704. data[chunk] = null;
  1705. }
  1706. }
  1707. return value;
  1708. }
  1709. /**
  1710. * This version of putIdentifier is needed to avoid fluffing
  1711. * all of the paths to ID attributes when a node object is
  1712. * created that contains an ID attribute.
  1713. */
  1714. private final void putIdentifier0(String idName, Element element) {
  1715. if (DEBUG_IDS) {
  1716. System.out.println("putIdentifier0("+
  1717. idName+", "+
  1718. element+')');
  1719. }
  1720. // create hashtable
  1721. if (identifiers == null) {
  1722. identifiers = new java.util.Hashtable();
  1723. }
  1724. // save ID and its associated element
  1725. identifiers.put(idName, element);
  1726. } // putIdentifier0(String,Element)
  1727. /** Prints the ID array. */
  1728. private static void print(int values[], int start, int end,
  1729. int middle, int target) {
  1730. if (DEBUG_IDS) {
  1731. System.out.print(start);
  1732. System.out.print(" [");
  1733. for (int i = start; i < end; i++) {
  1734. if (middle == i) {
  1735. System.out.print("!");
  1736. }
  1737. System.out.print(values[i]);
  1738. if (values[i] == target) {
  1739. System.out.print("*");
  1740. }
  1741. if (i < end - 1) {
  1742. System.out.print(" ");
  1743. }
  1744. }
  1745. System.out.println("] "+end);
  1746. }
  1747. } // print(int[],int,int,int,int)
  1748. //
  1749. // Classes
  1750. //
  1751. /**
  1752. * A simple integer vector.
  1753. */
  1754. static class IntVector {
  1755. //
  1756. // Data
  1757. //
  1758. /** Data. */
  1759. private int data[];
  1760. /** Size. */
  1761. private int size;
  1762. //
  1763. // Public methods
  1764. //
  1765. /** Returns the length of this vector. */
  1766. public int size() {
  1767. return size;
  1768. }
  1769. /** Returns the element at the specified index. */
  1770. public int elementAt(int index) {
  1771. return data[index];
  1772. }
  1773. /** Appends an element to the end of the vector. */
  1774. public void addElement(int element) {
  1775. ensureCapacity(size + 1);
  1776. data[size++] = element;
  1777. }
  1778. /** Clears the vector. */
  1779. public void removeAllElements() {
  1780. size = 0;
  1781. }
  1782. //
  1783. // Private methods
  1784. //
  1785. /** Makes sure that there is enough storage. */
  1786. private void ensureCapacity(int newsize) {
  1787. if (data == null) {
  1788. data = new int[newsize + 15];
  1789. }
  1790. else if (newsize > data.length) {
  1791. int newdata[] = new int[newsize + 15];
  1792. System.arraycopy(data, 0, newdata, 0, data.length);
  1793. data = newdata;
  1794. }
  1795. } // ensureCapacity(int)
  1796. } // class IntVector
  1797. } // class DeferredDocumentImpl