- /*
- * @(#)ContentModel.java 1.6 00/02/02
- *
- * Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the proprietary information of Sun Microsystems, Inc.
- * Use is subject to license terms.
- *
- */
-
- package javax.swing.text.html.parser;
-
- import java.util.Vector;
- import java.util.Enumeration;
- import java.io.*;
-
-
- /**
- * A representation of a content model. A content model is
- * basically a restricted BNF expression. It is restricted in
- * the sense that it must be deterministic. This means that you
- * don't have to represent it as a finite state automata.<p>
- * See Annex H on page 556 of the SGML handbook for more information.
- *
- * @author Arthur van Hoff
- * @version 1.6,02/02/00
- *
- */
- public final class ContentModel implements Serializable {
- /**
- * Type. Either '*', '?', '+', ',', '|', '&'.
- */
- public int type;
-
- /**
- * The content. Either an Element or a ContentModel.
- */
- public Object content;
-
- /**
- * The next content model (in a ',', '|' or '&' expression).
- */
- public ContentModel next;
-
- public ContentModel() {
- }
-
- /**
- * Create a content model for an element.
- */
- public ContentModel(Element content) {
- this(0, content, null);
- }
-
- /**
- * Create a content model of a particular type.
- */
- public ContentModel(int type, ContentModel content) {
- this(type, content, null);
- }
-
- /**
- * Create a content model of a particular type.
- */
- public ContentModel(int type, Object content, ContentModel next) {
- this.type = type;
- this.content = content;
- this.next = next;
- }
-
- /**
- * Return true if the content model could
- * match an empty input stream.
- */
- public boolean empty() {
- switch (type) {
- case '*':
- case '?':
- return true;
-
- case '+':
- case '|':
- for (ContentModel m = (ContentModel)content ; m != null ; m = m.next) {
- if (m.empty()) {
- return true;
- }
- }
- return false;
-
- case ',':
- case '&':
- for (ContentModel m = (ContentModel)content ; m != null ; m = m.next) {
- if (!m.empty()) {
- return false;
- }
- }
- return true;
-
- default:
- return false;
- }
- }
-
- /**
- * Update elemVec with the list of elements that are
- * part of the this contentModel.
- */
- public void getElements(Vector elemVec) {
- switch (type) {
- case '*':
- case '?':
- case '+':
- ((ContentModel)content).getElements(elemVec);
- break;
- case ',':
- case '|':
- case '&':
- for (ContentModel m=(ContentModel)content; m != null; m=m.next){
- m.getElements(elemVec);
- }
- break;
- default:
- elemVec.addElement(content);
- }
- }
-
- private boolean valSet[];
- private boolean val[];
- // A cache used by first(). This cache was found to speed parsing
- // by about 10% (based on measurements of the 4-12 code base after
- // buffering was fixed).
-
- /**
- * Return true if the token could potentially be the
- * first token in the input stream.
- */
- public boolean first(Object token) {
- switch (type) {
- case '*':
- case '?':
- case '+':
- return ((ContentModel)content).first(token);
-
- case ',':
- for (ContentModel m = (ContentModel)content ; m != null ; m = m.next) {
- if (m.first(token)) {
- return true;
- }
- if (!m.empty()) {
- return false;
- }
- }
- return false;
-
- case '|':
- case '&': {
- Element e = (Element) token;
- if (valSet == null) {
- valSet = new boolean[Element.maxIndex + 1];
- val = new boolean[Element.maxIndex + 1];
- // All Element instances are created before this ever executes
- }
- if (valSet[e.index]) {
- return val[e.index];
- }
- for (ContentModel m = (ContentModel)content ; m != null ; m = m.next) {
- if (m.first(token)) {
- val[e.index] = true;
- break;
- }
- }
- valSet[e.index] = true;
- return val[e.index];
- }
-
- default:
- return (content == token);
- }
- }
-
- /**
- * Return the element that must be next.
- */
- public Element first() {
- switch (type) {
- case '&':
- case '|':
- case '*':
- case '?':
- return null;
-
- case '+':
- case ',':
- return ((ContentModel)content).first();
-
- default:
- return (Element)content;
- }
- }
-
- /**
- * Convert to a string.
- */
- public String toString() {
- switch (type) {
- case '*':
- return content + "*";
- case '?':
- return content + "?";
- case '+':
- return content + "+";
-
- case ',':
- case '|':
- case '&':
- char data[] = {' ', (char)type, ' '};
- String str = "";
- for (ContentModel m = (ContentModel)content ; m != null ; m = m.next) {
- str = str + m;
- if (m.next != null) {
- str += new String(data);
- }
- }
- return "(" + str + ")";
-
- default:
- return content.toString();
- }
- }
- }