1. /*
  2. * @(#)DTD.java 1.10 00/02/02
  3. *
  4. * Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing.text.html.parser;
  11. import java.io.PrintStream;
  12. import java.io.File;
  13. import java.io.FileInputStream;
  14. import java.io.InputStream;
  15. import java.io.IOException;
  16. import java.io.FileNotFoundException;
  17. import java.io.BufferedInputStream;
  18. import java.io.DataInputStream;
  19. import java.util.Hashtable;
  20. import java.util.Vector;
  21. import java.util.BitSet;
  22. import java.util.StringTokenizer;
  23. import java.util.Enumeration;
  24. import java.util.Properties;
  25. import java.net.URL;
  26. /**
  27. * The representation of an SGML DTD. This is produced by the DTDParser.
  28. * The resulting DTD object describes a document syntax and is needed
  29. * to parser HTML documents using the Parser. It contains a list of
  30. * elements and their attributes as well as a list of entities defined
  31. * in the DTD.
  32. *
  33. * @see Element
  34. * @see AttributeList
  35. * @see ContentModel
  36. * @see DTDParser
  37. * @see Parser
  38. * @author Arthur van Hoff
  39. * @version 1.10 02/02/00
  40. */
  41. public
  42. class DTD implements DTDConstants {
  43. public String name;
  44. public Vector elements = new Vector();
  45. public Hashtable elementHash = new Hashtable();
  46. public Hashtable entityHash = new Hashtable();
  47. public final Element pcdata = getElement("#pcdata");
  48. public final Element html = getElement("html");
  49. public final Element meta = getElement("meta");
  50. public final Element base = getElement("base");
  51. public final Element isindex = getElement("isindex");
  52. public final Element head = getElement("head");
  53. public final Element body = getElement("body");
  54. public final Element applet = getElement("applet");
  55. public final Element param = getElement("param");
  56. public final Element p = getElement("p");
  57. public final Element title = getElement("title");
  58. final Element style = getElement("style");
  59. final Element link = getElement("link");
  60. public static int FILE_VERSION = 1;
  61. /**
  62. * Create a new DTD.
  63. */
  64. protected DTD(String name) {
  65. this.name = name;
  66. defEntity("#RE", GENERAL, '\r');
  67. defEntity("#RS", GENERAL, '\n');
  68. defEntity("#SPACE", GENERAL, ' ');
  69. defineElement("unknown", EMPTY, false, true, null, null, null, null);
  70. }
  71. /**
  72. * Get the name of the DTD.
  73. */
  74. public String getName() {
  75. return name;
  76. }
  77. /**
  78. * Get an entity by name.
  79. */
  80. public Entity getEntity(String name) {
  81. return (Entity)entityHash.get(name);
  82. }
  83. /**
  84. * Get a character entity.
  85. */
  86. public Entity getEntity(int ch) {
  87. return (Entity)entityHash.get(new Integer(ch));
  88. }
  89. /**
  90. * Return true if the element is part of the dtd
  91. * else false.
  92. */
  93. boolean elementExists(String name) {
  94. Element e = (Element)elementHash.get(name);
  95. return ((e == null) ? false : true);
  96. }
  97. /**
  98. * Get an element by name. A new element is
  99. * created if the element doesn't exist.
  100. */
  101. public Element getElement(String name) {
  102. Element e = (Element)elementHash.get(name);
  103. if (e == null) {
  104. e = new Element(name, elements.size());
  105. elements.addElement(e);
  106. elementHash.put(name, e);
  107. }
  108. return e;
  109. }
  110. /**
  111. * Get an element by index.
  112. */
  113. public Element getElement(int index) {
  114. return (Element)elements.elementAt(index);
  115. }
  116. /**
  117. * Define an entity.
  118. */
  119. public Entity defineEntity(String name, int type, char data[]) {
  120. Entity ent = (Entity)entityHash.get(name);
  121. if (ent == null) {
  122. ent = new Entity(name, type, data);
  123. entityHash.put(name, ent);
  124. if (((type & GENERAL) != 0) && (data.length == 1)) {
  125. switch (type & ~GENERAL) {
  126. case CDATA:
  127. case SDATA:
  128. entityHash.put(new Integer(data[0]), ent);
  129. break;
  130. }
  131. }
  132. }
  133. return ent;
  134. }
  135. /**
  136. * Define an element.
  137. */
  138. public Element defineElement(String name, int type,
  139. boolean omitStart, boolean omitEnd, ContentModel content,
  140. BitSet exclusions, BitSet inclusions, AttributeList atts) {
  141. Element e = getElement(name);
  142. e.type = type;
  143. e.oStart = omitStart;
  144. e.oEnd = omitEnd;
  145. e.content = content;
  146. e.exclusions = exclusions;
  147. e.inclusions = inclusions;
  148. e.atts = atts;
  149. return e;
  150. }
  151. /**
  152. * Define the attributes of an element.
  153. */
  154. public void defineAttributes(String name, AttributeList atts) {
  155. Element e = getElement(name);
  156. e.atts = atts;
  157. }
  158. /**
  159. * Define a character entity.
  160. */
  161. public Entity defEntity(String name, int type, int ch) {
  162. char data[] = {(char)ch};
  163. return defineEntity(name, type, data);
  164. }
  165. /**
  166. * Define an entity.
  167. */
  168. protected Entity defEntity(String name, int type, String str) {
  169. int len = str.length();
  170. char data[] = new char[len];
  171. str.getChars(0, len, data, 0);
  172. return defineEntity(name, type, data);
  173. }
  174. /**
  175. * Define an element.
  176. */
  177. protected Element defElement(String name, int type,
  178. boolean omitStart, boolean omitEnd, ContentModel content,
  179. String[] exclusions, String[] inclusions, AttributeList atts) {
  180. BitSet excl = null;
  181. if (exclusions != null && exclusions.length > 0) {
  182. excl = new BitSet();
  183. for (int i = 0; i < exclusions.length; i++) {
  184. String str = exclusions[i];
  185. if (str.length() > 0) {
  186. excl.set(getElement(str).getIndex());
  187. }
  188. }
  189. }
  190. BitSet incl = null;
  191. if (inclusions != null && inclusions.length > 0) {
  192. incl = new BitSet();
  193. for (int i = 0; i < inclusions.length; i++) {
  194. String str = inclusions[i];
  195. if (str.length() > 0) {
  196. incl.set(getElement(str).getIndex());
  197. }
  198. }
  199. }
  200. return defineElement(name, type, omitStart, omitEnd, content, excl, incl, atts);
  201. }
  202. /**
  203. * Define an attribute list
  204. */
  205. protected AttributeList defAttributeList(String name, int type, int modifier, String value, String values, AttributeList atts) {
  206. Vector vals = null;
  207. if (values != null) {
  208. vals = new Vector();
  209. for (StringTokenizer s = new StringTokenizer(values, "|") ; s.hasMoreTokens() ;) {
  210. String str = s.nextToken();
  211. if (str.length() > 0) {
  212. vals.addElement(str);
  213. }
  214. }
  215. }
  216. return new AttributeList(name, type, modifier, value, vals, atts);
  217. }
  218. /**
  219. * Define a content model
  220. */
  221. protected ContentModel defContentModel(int type, Object obj, ContentModel next) {
  222. return new ContentModel(type, obj, next);
  223. }
  224. /**
  225. * Return a string representation.
  226. */
  227. public String toString() {
  228. return name;
  229. }
  230. /**
  231. * The hashtable of DTDs.
  232. */
  233. static Hashtable dtdHash = new Hashtable();
  234. public static void putDTDHash(String name, DTD dtd) {
  235. dtdHash.put(name, dtd);
  236. }
  237. /**
  238. * Get a DTD.
  239. */
  240. public static DTD getDTD(String name) throws IOException {
  241. name = name.toLowerCase();
  242. DTD dtd = (DTD)dtdHash.get(name);
  243. if (dtd == null)
  244. dtd = new DTD(name);
  245. return dtd;
  246. }
  247. public void read(DataInputStream in) throws IOException {
  248. if (in.readInt() != FILE_VERSION) {
  249. }
  250. //
  251. // Read the list of names
  252. //
  253. String[] names = new String[in.readShort()];
  254. for (int i = 0; i < names.length; i++) {
  255. names[i] = in.readUTF();
  256. }
  257. //
  258. // Read the entities
  259. //
  260. int num = in.readShort();
  261. for (int i = 0; i < num; i++) {
  262. short nameId = in.readShort();
  263. int type = in.readByte();
  264. String name = in.readUTF();
  265. defEntity(names[nameId], type | GENERAL, name);
  266. }
  267. // Read the elements
  268. //
  269. num = in.readShort();
  270. for (int i = 0; i < num; i++) {
  271. short nameId = in.readShort();
  272. int type = in.readByte();
  273. byte flags = in.readByte();
  274. ContentModel m = readContentModel(in, names);
  275. String[] exclusions = readNameArray(in, names);
  276. String[] inclusions = readNameArray(in, names);
  277. AttributeList atts = readAttributeList(in, names);
  278. defElement(names[nameId], type,
  279. ((flags & 0x01) != 0), ((flags & 0x02) != 0),
  280. m, exclusions, inclusions, atts);
  281. }
  282. }
  283. private ContentModel readContentModel(DataInputStream in, String[] names)
  284. throws IOException {
  285. byte flag = in.readByte();
  286. switch(flag) {
  287. case 0: // null
  288. return null;
  289. case 1: { // content_c
  290. int type = in.readByte();
  291. ContentModel m = readContentModel(in, names);
  292. ContentModel next = readContentModel(in, names);
  293. return defContentModel(type, m, next);
  294. }
  295. case 2: { // content_e
  296. int type = in.readByte();
  297. Element el = getElement(names[in.readShort()]);
  298. ContentModel next = readContentModel(in, names);
  299. return defContentModel(type, el, next);
  300. }
  301. default:
  302. throw new IOException("bad bdtd");
  303. }
  304. }
  305. private String[] readNameArray(DataInputStream in, String[] names)
  306. throws IOException {
  307. int num = in.readShort();
  308. if (num == 0) {
  309. return null;
  310. }
  311. String[] result = new String[num];
  312. for (int i = 0; i < num; i++) {
  313. result[i] = names[in.readShort()];
  314. }
  315. return result;
  316. }
  317. private AttributeList readAttributeList(DataInputStream in, String[] names)
  318. throws IOException {
  319. AttributeList result = null;
  320. for (int num = in.readByte(); num > 0; --num) {
  321. short nameId = in.readShort();
  322. int type = in.readByte();
  323. int modifier = in.readByte();
  324. short valueId = in.readShort();
  325. String value = (valueId == -1) ? null : names[valueId];
  326. Vector values = null;
  327. short numValues = in.readShort();
  328. if (numValues > 0) {
  329. values = new Vector(numValues);
  330. for (int i = 0; i < numValues; i++) {
  331. values.addElement(names[in.readShort()]);
  332. }
  333. }
  334. result = new AttributeList(names[nameId], type, modifier, value,
  335. values, result);
  336. // We reverse the order of the linked list by doing this, but
  337. // that order isn't important.
  338. }
  339. return result;
  340. }
  341. }