1. /*
  2. * $Id: Doctype.java,v 1.3 2001/05/23 21:40:04 edwingo Exp $
  3. *
  4. * The Apache Software License, Version 1.1
  5. *
  6. *
  7. * Copyright (c) 2000 The Apache Software Foundation. All rights
  8. * reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. *
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. *
  17. * 2. Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in
  19. * the documentation and/or other materials provided with the
  20. * distribution.
  21. *
  22. * 3. The end-user documentation included with the redistribution,
  23. * if any, must include the following acknowledgment:
  24. * "This product includes software developed by the
  25. * Apache Software Foundation (http://www.apache.org/)."
  26. * Alternately, this acknowledgment may appear in the software itself,
  27. * if and wherever such third-party acknowledgments normally appear.
  28. *
  29. * 4. The names "Crimson" and "Apache Software Foundation" must
  30. * not be used to endorse or promote products derived from this
  31. * software without prior written permission. For written
  32. * permission, please contact apache@apache.org.
  33. *
  34. * 5. Products derived from this software may not be called "Apache",
  35. * nor may "Apache" appear in their name, without prior written
  36. * permission of the Apache Software Foundation.
  37. *
  38. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  39. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  40. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  41. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  42. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  43. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  44. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  45. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  46. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  47. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  48. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  49. * SUCH DAMAGE.
  50. * ====================================================================
  51. *
  52. * This software consists of voluntary contributions made by many
  53. * individuals on behalf of the Apache Software Foundation and was
  54. * originally based on software copyright (c) 1999, Sun Microsystems, Inc.,
  55. * http://www.sun.com. For more information on the Apache Software
  56. * Foundation, please see <http://www.apache.org/>.
  57. */
  58. package org.apache.crimson.tree;
  59. import java.io.OutputStreamWriter;
  60. import java.io.OutputStream;
  61. import java.io.Writer;
  62. import java.io.IOException;
  63. import java.util.Dictionary;
  64. import java.util.Enumeration;
  65. import java.util.Hashtable;
  66. import org.w3c.dom.*;
  67. import org.xml.sax.SAXException;
  68. /**
  69. * Class representing a DTD in DOM Level 1; this class exists purely
  70. * for editor support, and is of dubious interest otherwise.
  71. *
  72. * @author David Brownell
  73. * @version $Revision: 1.3 $
  74. */
  75. final class Doctype extends NodeBase implements DocumentType
  76. {
  77. // Stuff generated during parsing ...
  78. private String name;
  79. private Nodemap entities;
  80. private Nodemap notations;
  81. // ... stuff assigned by apps separately
  82. private String publicId;
  83. private String systemId;
  84. private String internalSubset;
  85. /**
  86. * XXX Obsolete, but keep it for backwards compatibility
  87. */
  88. // package private
  89. Doctype (String pub, String sys, String subset)
  90. {
  91. publicId = pub;
  92. systemId = sys;
  93. internalSubset = subset;
  94. }
  95. /**
  96. * New DOM Level 2 constructor
  97. */
  98. // package private
  99. Doctype(String name, String publicId, String systemId,
  100. String internalSubset)
  101. {
  102. this.name = name;
  103. this.publicId = publicId;
  104. this.systemId = systemId;
  105. this.internalSubset = internalSubset;
  106. entities = new Nodemap ();
  107. notations = new Nodemap ();
  108. }
  109. // package private
  110. void setPrintInfo (String pub, String sys, String subset)
  111. {
  112. publicId = pub;
  113. systemId = sys;
  114. internalSubset = subset;
  115. }
  116. /**
  117. * Writes out a textual DTD, trusting that any internal subset text
  118. * is in fact well formed XML.
  119. */
  120. public void writeXml (XmlWriteContext context) throws IOException
  121. {
  122. Writer out = context.getWriter ();
  123. Element root = getOwnerDocument ().getDocumentElement ();
  124. out.write ("<!DOCTYPE ");
  125. out.write (root == null ? "UNKNOWN-ROOT" : root.getNodeName ());
  126. if (systemId != null) {
  127. if (publicId != null) {
  128. out.write (" PUBLIC '");
  129. out.write (publicId);
  130. out.write ("' '");
  131. } else
  132. out.write (" SYSTEM '");
  133. out.write (systemId);
  134. out.write ("'");
  135. }
  136. if (internalSubset != null) {
  137. out.write (XmlDocument.eol);
  138. out.write ("[");
  139. out.write (internalSubset);
  140. out.write ("]");
  141. }
  142. out.write (">");
  143. out.write (XmlDocument.eol);
  144. }
  145. /** DOM: Returns DOCUMENT_TYPE_NODE */
  146. public short getNodeType ()
  147. { return DOCUMENT_TYPE_NODE; }
  148. /** DOM: Returns the name declared for the document root node. */
  149. public String getName ()
  150. { return name; }
  151. /** DOM: Returns the name declared for the document root node. */
  152. public String getNodeName ()
  153. { return name; }
  154. /**
  155. * Only implement shallow clone for now, which is allowed in DOM Level 2.
  156. */
  157. public Node cloneNode(boolean deep)
  158. {
  159. Doctype retval = new Doctype(name, publicId, systemId, internalSubset);
  160. retval.setOwnerDocument((XmlDocument)getOwnerDocument());
  161. return retval;
  162. }
  163. /**
  164. * DOM: Returns the internal, external, and unparsed entities
  165. * declared in this DTD.
  166. */
  167. public NamedNodeMap getEntities ()
  168. { return entities; }
  169. /** DOM: Returns the notations declared in this DTD. */
  170. public NamedNodeMap getNotations ()
  171. { return notations; }
  172. /**
  173. * The public identifier of the external subset.
  174. * @since DOM Level 2
  175. */
  176. public String getPublicId() {
  177. return publicId;
  178. }
  179. /**
  180. * The system identifier of the external subset.
  181. * @since DOM Level 2
  182. */
  183. public String getSystemId() {
  184. return systemId;
  185. }
  186. /**
  187. * The internal subset as a string.
  188. * @since DOM Level 2
  189. */
  190. public String getInternalSubset() {
  191. return internalSubset;
  192. }
  193. protected void setOwnerDocument(XmlDocument doc) {
  194. super.setOwnerDocument (doc);
  195. if (entities != null)
  196. for (int i = 0; entities.item (i) != null; i++)
  197. ((NodeBase)entities.item (i)).setOwnerDocument (doc);
  198. if (notations != null)
  199. for (int i = 0; notations.item (i) != null; i++)
  200. ((NodeBase)notations.item (i)).setOwnerDocument (doc);
  201. }
  202. /** Adds a notation node. */
  203. // package private
  204. void addNotation (String name, String pub, String sys)
  205. {
  206. NotationNode node = new NotationNode (name, pub, sys);
  207. node.setOwnerDocument ((XmlDocument)getOwnerDocument ());
  208. notations.setNamedItem (node);
  209. }
  210. /**
  211. * Adds an entity node for an external entity, which
  212. * could be parsed or unparsed.
  213. */
  214. // package private
  215. void addEntityNode (String name, String pub, String sys, String not)
  216. {
  217. EntityNode node = new EntityNode (name, pub, sys, not);
  218. node.setOwnerDocument ((XmlDocument)getOwnerDocument ());
  219. entities.setNamedItem (node);
  220. }
  221. /** Adds an entity node for an internal parsed entity. */
  222. // package private
  223. void addEntityNode (String name, String value)
  224. {
  225. if ("lt".equals (name) || "gt".equals (name)
  226. || "apos".equals (name) || "quot".equals (name)
  227. || "amp".equals (name))
  228. return; // predeclared, immutable
  229. EntityNode node = new EntityNode (name, value);
  230. node.setOwnerDocument ((XmlDocument)getOwnerDocument ());
  231. entities.setNamedItem (node);
  232. }
  233. /** Marks the sets of entities and notations as readonly. */
  234. // package private
  235. void setReadonly ()
  236. {
  237. entities.readonly = true;
  238. notations.readonly = true;
  239. }
  240. static class NotationNode extends NodeBase implements Notation
  241. {
  242. private String notation;
  243. private String publicId;
  244. private String systemId;
  245. NotationNode (String name, String pub, String sys)
  246. {
  247. notation = name;
  248. publicId = pub;
  249. systemId = sys;
  250. }
  251. public String getPublicId ()
  252. { return publicId; }
  253. public String getSystemId ()
  254. { return systemId; }
  255. public short getNodeType ()
  256. { return NOTATION_NODE; }
  257. public String getNodeName ()
  258. { return notation; }
  259. public Node cloneNode (boolean ignored)
  260. {
  261. NotationNode retval;
  262. retval = new NotationNode (notation, publicId, systemId);
  263. retval.setOwnerDocument ((XmlDocument)getOwnerDocument ());
  264. return retval;
  265. }
  266. public void writeXml (XmlWriteContext context) throws IOException
  267. {
  268. Writer out = context.getWriter ();
  269. out.write ("<!NOTATION ");
  270. out.write (notation);
  271. if (publicId != null) {
  272. out.write (" PUBLIC '");
  273. out.write (publicId);
  274. if (systemId != null) {
  275. out.write ("' '");
  276. out.write (systemId);
  277. }
  278. } else {
  279. out.write (" SYSTEM '");
  280. out.write (systemId);
  281. }
  282. out.write ("'>");
  283. }
  284. }
  285. // DOM permits the children to be null ... we do that consistently
  286. static class EntityNode extends NodeBase implements Entity
  287. {
  288. private String entityName;
  289. private String publicId;
  290. private String systemId;
  291. private String notation;
  292. private String value;
  293. EntityNode (String name, String pub, String sys, String not)
  294. {
  295. entityName = name;
  296. publicId = pub;
  297. systemId = sys;
  298. notation = not;
  299. }
  300. EntityNode (String name, String value)
  301. {
  302. entityName = name;
  303. this.value = value;
  304. }
  305. public String getNodeName ()
  306. { return entityName; }
  307. public short getNodeType ()
  308. { return ENTITY_NODE; }
  309. public String getPublicId ()
  310. { return publicId; }
  311. public String getSystemId ()
  312. { return systemId; }
  313. public String getNotationName ()
  314. { return notation; }
  315. public Node cloneNode (boolean ignored)
  316. {
  317. EntityNode retval;
  318. retval = new EntityNode (entityName, publicId, systemId,
  319. notation);
  320. retval.setOwnerDocument ((XmlDocument)getOwnerDocument ());
  321. return retval;
  322. }
  323. public void writeXml (XmlWriteContext context) throws IOException
  324. {
  325. Writer out = context.getWriter ();
  326. out.write ("<!ENTITY ");
  327. out.write (entityName);
  328. if (value == null) {
  329. if (publicId != null) {
  330. out.write (" PUBLIC '");
  331. out.write (publicId);
  332. out.write ("' '");
  333. } else
  334. out.write (" SYSTEM '");
  335. out.write (systemId);
  336. out.write ("'");
  337. if (notation != null) {
  338. out.write (" NDATA ");
  339. out.write (notation);
  340. }
  341. } else {
  342. out.write (" \"");
  343. int length = value.length ();
  344. for (int i = 0; i < length; i++) {
  345. char c = value.charAt (i);
  346. if (c == '"')
  347. out.write (""");
  348. else
  349. out.write (c);
  350. }
  351. out.write ('"');
  352. }
  353. out.write (">");
  354. }
  355. }
  356. static class Nodemap implements NamedNodeMap
  357. {
  358. // package private
  359. boolean readonly;
  360. // package private
  361. java.util.Vector list = new java.util.Vector ();
  362. // XXX copied from AttributeSet; share implementation!
  363. public Node getNamedItem (String name)
  364. {
  365. int length = list.size ();
  366. Node value;
  367. for (int i = 0; i < length; i++) {
  368. value = item (i);
  369. if (value.getNodeName ().equals (name))
  370. return value;
  371. }
  372. return null;
  373. }
  374. /**
  375. * <b>DOM2:</b>
  376. */
  377. public Node getNamedItemNS(String namespaceURI, String localName) {
  378. return null;
  379. }
  380. // XXX copied from AttributeSet; share implementation!
  381. public int getLength ()
  382. {
  383. return list.size ();
  384. }
  385. // XXX copied from AttributeSet; share implementation!
  386. public Node item (int index)
  387. {
  388. if (index < 0 || index >= list.size ())
  389. return null;
  390. return (Node) list.elementAt (index);
  391. }
  392. public Node removeNamedItem (String name)
  393. throws DOMException
  394. {
  395. throw new DomEx (DOMException.NO_MODIFICATION_ALLOWED_ERR);
  396. }
  397. /**
  398. * <b>DOM2:</b>
  399. */
  400. public Node removeNamedItemNS(String namespaceURI, String localName)
  401. throws DOMException
  402. {
  403. throw new DomEx(DOMException.NO_MODIFICATION_ALLOWED_ERR);
  404. }
  405. // caller guarantees (e.g. from parser) uniqueness
  406. public Node setNamedItem (Node item) throws DOMException
  407. {
  408. if (readonly)
  409. throw new DomEx (DOMException.NO_MODIFICATION_ALLOWED_ERR);
  410. list.addElement (item);
  411. return null;
  412. }
  413. /**
  414. * <b>DOM2:</b>
  415. */
  416. public Node setNamedItemNS(Node arg) throws DOMException {
  417. if (readonly) {
  418. throw new DomEx(DomEx.NO_MODIFICATION_ALLOWED_ERR);
  419. }
  420. list.addElement(arg);
  421. return null;
  422. }
  423. }
  424. }