001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package javax.swing.text.html.parser;
018:
019: import java.io.DataInputStream;
020: import java.io.IOException;
021: import java.util.BitSet;
022: import java.util.Hashtable;
023: import java.util.Vector;
024:
025: public class DTD implements DTDConstants {
026: public static final int FILE_VERSION = 1;
027:
028: public String name;
029:
030: public Vector<Element> elements = new Vector<Element>();
031:
032: public Hashtable<String, Element> elementHash = new Hashtable<String, Element>();
033: public Hashtable<Object, Entity> entityHash = new Hashtable<Object, Entity>();
034:
035: public final Element pcdata;
036: public final Element html;
037: public final Element meta;
038: public final Element base;
039: public final Element isindex;
040: public final Element head;
041: public final Element body;
042: public final Element applet;
043: public final Element param;
044: public final Element p;
045: public final Element title;
046:
047: private static final Hashtable dtdHash = new Hashtable();
048:
049: private static final String pattern = "(\\|)+";
050:
051: private boolean readDTD;
052:
053: /**
054: * Created DTD will not be pushed to DTD hash.
055: * @throws IllegalArgumentException if name equals to null
056: */
057: public static DTD getDTD(final String name) throws IOException {
058: String key = name.toLowerCase();
059: Object dtd = dtdHash.get(key);
060: return dtd == null ? new DTD(name.toLowerCase()) : (DTD) dtd;
061: }
062:
063: /**
064: *
065: * @throws IllegalArgumentException if dtd or name equal to null
066: */
067: public static void putDTDHash(final String name, final DTD dtd) {
068: dtdHash.put(name.toLowerCase(), dtd);
069: }
070:
071: protected DTD(final String name) {
072: //TODO may be it need change the order
073: this .name = name;
074:
075: pcdata = createDefaultElement(
076: HTMLConstants.PCDATA_ELEMENT_NAME, 0);
077: putElement(pcdata);
078:
079: html = createDefaultElement(HTMLConstants.HTML_ELEMENT_NAME, 1);
080: putElement(html);
081:
082: meta = createDefaultElement(HTMLConstants.META_ELEMENT_NAME, 2);
083: putElement(meta);
084:
085: base = createDefaultElement(HTMLConstants.BASE_ELEMENT_NAME, 3);
086: putElement(base);
087:
088: isindex = createDefaultElement(
089: HTMLConstants.ISINDEX_ELEMENT_NAME, 4);
090: putElement(isindex);
091:
092: head = createDefaultElement(HTMLConstants.HEAD_ELEMENT_NAME, 5);
093: putElement(head);
094:
095: body = createDefaultElement(HTMLConstants.BODY_ELEMENT_NAME, 6);
096: putElement(body);
097:
098: applet = createDefaultElement(
099: HTMLConstants.APPLET_ELEMENT_NAME, 7);
100: putElement(applet);
101:
102: param = createDefaultElement(HTMLConstants.PARAM_ELEMENT_NAME,
103: 8);
104: putElement(param);
105:
106: p = createDefaultElement(HTMLConstants.P_ELEMENT_NAME, 9);
107: putElement(p);
108:
109: title = createDefaultElement(HTMLConstants.TITLE_ELEMENT_NAME,
110: 10);
111: putElement(title);
112:
113: putElement(createDefaultElement(
114: HTMLConstants.STYLE_ELEMENT_NAME, 11));
115: putElement(createDefaultElement(
116: HTMLConstants.LINK_ELEMENT_NAME, 12));
117: putElement(createDefaultElement(
118: HTMLConstants.SCRIPT_ELEMENT_NAME, 13));
119:
120: putElement(new Element(14, HTMLConstants.UNKNOWN_ELEMENT_NAME,
121: false, true, null, null, EMPTY, null, null, null));
122:
123: entityHash.put(HTMLConstants.SPACE_ENTITY_NAME,
124: createDefaultEntity(HTMLConstants.SPACE_ENTITY_NAME,
125: " "));
126: entityHash
127: .put(HTMLConstants.RS_ENTITY_NAME, createDefaultEntity(
128: HTMLConstants.RS_ENTITY_NAME, "\n"));
129: entityHash
130: .put(HTMLConstants.RE_ENTITY_NAME, createDefaultEntity(
131: HTMLConstants.RE_ENTITY_NAME, "\r"));
132: }
133:
134: private void putElement(final Element element) {
135: elements.add(element);
136: elementHash.put(element.getName(), element);
137: }
138:
139: private Element createDefaultElement(final String name,
140: final int index) {
141: return new Element(index, name, false, false, null, null, ANY,
142: null, null, null);
143: }
144:
145: private Entity createDefaultEntity(final String name,
146: final String data) {
147: return new Entity(name, 0, data, true, false);
148: }
149:
150: public void read(final DataInputStream stream) throws IOException {
151: // converts from DataInputStream into a byte array
152: byte[] enc = new byte[stream.available()];
153: stream.read(enc);
154:
155: // decode the byte array
156: Asn1Dtd asn1 = new Asn1Dtd(enc);
157:
158: // sets attributes
159: asn1.getDTD(this );
160: setReading(true);
161: }
162:
163: public String toString() {
164: return name;
165: }
166:
167: protected ContentModel defContentModel(final int type,
168: final Object content, final ContentModel next) {
169: return new ContentModel(type, content, next);
170: }
171:
172: /**
173: *
174: * @param values attributes split by '|'
175: */
176: protected AttributeList defAttributeList(final String name,
177: final int type, final int modifier, final String value,
178: final String values, final AttributeList next) {
179:
180: return new AttributeList(name, type, modifier, value,
181: createAttributeNamesVector(values), next);
182: }
183:
184: private Vector createAttributeNamesVector(final String values) {
185: if (values == null) {
186: return null;
187: }
188: Vector result = new Vector();
189: String[] tokens = values.split(pattern);
190: for (int i = 0; i < tokens.length; i++) {
191: String token = tokens[i];
192: if (!"".equals(token)) {
193: result.add(token);
194: }
195: }
196: return result;
197: }
198:
199: /**
200: * If element exists but doesn't correspond to this parameters, it will be
201: * updated.
202: */
203: protected Element defElement(final String name, final int type,
204: final boolean oStart, final boolean oEnd,
205: final ContentModel content, final String[] exclusions,
206: final String[] inclusions, final AttributeList atts) {
207: return defineElement(name, type, oStart, oEnd, content,
208: createBitSetByStrings(exclusions),
209: createBitSetByStrings(inclusions), atts);
210:
211: }
212:
213: private BitSet createBitSetByStrings(final String[] names) {
214: if (names == null) {
215: return null;
216: }
217: BitSet result = new BitSet();
218: for (int i = 0; i < names.length; i++) {
219: Element elem = (Element) elementHash.get(names[i]);
220: if (elem == null) {
221: elem = defineElement(names[i], DTDConstants.ANY, false,
222: false, null, null, null, null);
223: }
224: if (!names[i].equals("")) {
225: result.set(elem.getIndex());
226: }
227: }
228:
229: return result;
230: }
231:
232: protected Entity defEntity(final String name, final int type,
233: final String str) {
234: // return defineEntity(name, type, str == null ? null : str.toCharArray());
235: return defineEntity(name, type, str.toCharArray());
236: }
237:
238: public Entity defEntity(final String name, final int type,
239: final int ch) {
240: return defineEntity(name, type, new char[] { (char) ch });
241: }
242:
243: /**
244: * Updated attributes of corresponding element, if this one exists.
245: * Otherwise, new elements are created with these attributes and put to
246: * elementsHash.
247: */
248: public void defineAttributes(final String name,
249: final AttributeList atts) {
250: Object obj = elementHash.get(name);
251: Element elem;
252: if (obj == null) {
253: elem = createDefaultElement(name, elements.size());
254: putElement(elem);
255: } else {
256: elem = (Element) obj;
257: }
258: elem.atts = atts;
259: }
260:
261: /**
262: * If element exists but doesn't correspond to this parameters, it will be
263: * updated.
264: */
265: public Element defineElement(final String name, final int type,
266: final boolean omitStart, final boolean omitEnd,
267: final ContentModel contentModel, final BitSet exclusions,
268: final BitSet inclusions, final AttributeList atts) {
269: Object obj = elementHash.get(name);
270: Element result;
271: if (obj == null) {
272: result = new Element(elements.size(), name, omitStart,
273: omitEnd, exclusions, inclusions, type,
274: contentModel, atts, null);
275: putElement(result);
276: } else {
277: result = (Element) obj;
278: result.updateElement(result.index, name, omitStart,
279: omitEnd, exclusions, inclusions, type,
280: contentModel, atts, null);
281: }
282: return result;
283: }
284:
285: /**
286: * If entity with this name exists, it will not be updated.
287: */
288: public Entity defineEntity(final String name, final int type,
289: final char[] data) {
290: Object obj = entityHash.get(name);
291: Entity result;
292: if (obj == null) {
293: result = new Entity(name, type, data);
294: entityHash.put(name, result);
295: if (readDTD) {
296: for (int i = 0; i < data.length; i++) {
297: entityHash.put(Integer.valueOf(data[i]), result);
298: }
299: }
300: } else {
301: result = (Entity) obj;
302: }
303: return result;
304: }
305:
306: /**
307: *
308: * @return if index < 0 or elements.size() <= index returns null.
309: */
310: public Element getElement(final int index) {
311: // same as RI
312: return (Element) elements.elementAt(index);
313: }
314:
315: public Element getElement(final String name) {
316: Object obj = elementHash.get(name);
317: if (obj != null) {
318: return (Element) obj;
319: }
320: Element element = createDefaultElement(name, elements.size());
321: putElement(element);
322: return element;
323: }
324:
325: public Entity getEntity(final int index) {
326: return entityHash.get(Integer.valueOf(index));
327: }
328:
329: public Entity getEntity(final String name) {
330: return (Entity) entityHash.get(name);
331: }
332:
333: public String getName() {
334: return name;
335: }
336:
337: void setReading(boolean b) {
338: readDTD = b;
339: }
340:
341: boolean isRead() {
342: return readDTD;
343: }
344: }
|