/projects/netbeans-7.3/html.editor.lib/src/org/netbeans/modules/html/editor/lib/dtd/DTDParser.java
Java | 1183 lines | 959 code | 121 blank | 103 comment | 200 complexity | 6f832cb01c641e912652bb8969fd7324 MD5 | raw file
- /*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
- *
- * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
- * Other names may be trademarks of their respective owners.
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common
- * Development and Distribution License("CDDL") (collectively, the
- * "License"). You may not use this file except in compliance with the
- * License. You can obtain a copy of the License at
- * http://www.netbeans.org/cddl-gplv2.html
- * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
- * specific language governing permissions and limitations under the
- * License. When distributing the software, include this License Header
- * Notice in each file and include the License file at
- * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the GPL Version 2 section of the License file that
- * accompanied this code. If applicable, add the following below the
- * License Header, with the fields enclosed by brackets [] replaced by
- * your own identifying information:
- * "Portions Copyrighted [year] [name of copyright owner]"
- *
- * Contributor(s):
- *
- * The Original Software is NetBeans. The Initial Developer of the Original
- * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
- * Microsystems, Inc. All Rights Reserved.
- *
- * If you wish your version of this file to be governed by only the CDDL
- * or only the GPL Version 2, indicate your decision by adding
- * "[Contributor] elects to include this software in this distribution
- * under the [CDDL or GPL Version 2] license." If you do not indicate a
- * single choice of license, a recipient has the option to distribute
- * your version of this file under either the CDDL, the GPL Version 2 or
- * to extend the choice of license to its licensees as provided above.
- * However, if you add GPL Version 2 code and therefore, elected the GPL
- * Version 2 license, then the option applies only if the new code is
- * made subject to such option by the copyright holder.
- */
- package org.netbeans.modules.html.editor.lib.dtd;
- import org.netbeans.modules.html.editor.lib.api.dtd.ReaderProvider;
- import java.io.Reader;
- import java.io.PushbackReader;
- import java.io.IOException;
- import java.lang.ref.WeakReference;
- import java.util.*;
- /**
- * !!! Includes !!!! String->DTD.Element
- * @author Petr Nejedly
- * @version 0.2
- */
- class DTDParser extends Object {
- // The provider used to provide the Readers for this DTD.
- private ReaderProvider provider = null;
- // Asks for Reader for given DTD.
- private Reader getReader( String identifier, String fileName ) {
- if( provider == null ) return null;
- return provider.getReaderForIdentifier( identifier, fileName );
- }
-
- /** Weak set for holding already created strings, to not create more
- * instances of the same string */
- private WeakHashSet stringCache = new WeakHashSet( 131, 0.75f );
-
- /** Weak set of attributes - helps sharing common attributes */
- private WeakHashSet attributes = new WeakHashSet( 23, 0.75f );
-
- /** Weak set of models */
- private WeakHashSet models = new WeakHashSet( 131, 0.75f );
-
- /** Weak set of Contents */
- private WeakHashSet contents = new WeakHashSet( 131, 0.75f );
-
- /** Temporal storage of all ContentLeafs that needs to get their
- * elements filled in at the end of parsing
- */
- Set leafs = new HashSet( 131, 0.75f );
- /** Map of all character references.
- * Mapping is String name -> DTD.CharRef instance */
- private SortedMap charRefs = new TreeMap();
-
- /** Map holding partially completed instances of Element.
- * Mapping is String name -> DTD.Element instance */
- private SortedMap elementMap = new TreeMap();
-
- /** Map holding entities during creation of DTD.
- * Mapping is String name -> String content.
- * This map should not be used for direct put(..), because entities
- * are defined by first declaration and can not be overriden.
- */
- private Map entityMap = new HashMap();
- public boolean xmlDTD; //if true we parse XML DTD, not SGML!
-
- public DTD createDTD( ReaderProvider provider, String identifier, String fileName ) throws WrongDTDException {
- this.provider = provider;
- xmlDTD = provider.isXMLContent(identifier);
- Reader reader = getReader( identifier, fileName );
- if( reader == null ) throw new WrongDTDException( "Can't open Reader for public identifier " + identifier ); // NOI18N
- try {
- parseDTD( new PushbackReader( reader, 1024*128 ) );
- } catch( IOException e ) {
- throw new WrongDTDException( "IOException during parsing: " + e.getMessage() ); // NOI18N
- }
- // fixup includes and excludes of all elements
- for( Iterator it = elementMap.values().iterator(); it.hasNext (); ) {
- DTD.Element elem = (DTD.Element)it.next();
- ContentModelImpl cm = (ContentModelImpl)elem.getContentModel();
- Set newIncs = new HashSet();
- for( Iterator incIter = cm.included.iterator(); incIter.hasNext (); ) {
- Object oldElem;
- Object subElem = oldElem = incIter.next();
- if( subElem instanceof String ) {
- String key = (String)subElem;
- subElem = elementMap.get( xmlDTD ? key : key.toUpperCase(Locale.ENGLISH) );
- }
- if( subElem == null ) {
- throw new WrongDTDException( "'" + oldElem + "' element referenced from " + elem.getName() + " not found throughout the DTD." ); // NOI18N
- }
- newIncs.add( subElem );
- }
- cm.included = newIncs;
-
- Set newExcs = new HashSet();
- for( Iterator excIter = cm.excluded.iterator(); excIter.hasNext (); ) {
- Object oldElem;
- Object subElem = oldElem = excIter.next();
- if( subElem instanceof String ) {
- String key = (String)subElem;
- subElem = elementMap.get( xmlDTD ? key : key.toUpperCase(Locale.ENGLISH) );
- }
- if( subElem == null ) {
- throw new WrongDTDException( "'" + oldElem + "' element referenced from " + elem.getName() + " not found throughout the DTD." ); // NOI18N
- }
- newExcs.add( subElem );
- }
- cm.excluded = newExcs;
- cm.hashcode = cm.content.hashCode() + 2*cm.included.hashCode() + 3*cm.excluded.hashCode();
- }
-
- // fixup content leafs
- for( Iterator it = leafs.iterator(); it.hasNext (); ) {
- ContentLeafImpl leaf = (ContentLeafImpl)it.next();
- leaf.elem = (DTD.Element)elementMap.get( leaf.elemName );
- }
-
- return new DTDImpl( identifier, elementMap, charRefs, xmlDTD );
- }
- /** Method for adding new entities to their map. Obeys the rule that
- * entity, once defined, can not be overriden */
- void addEntity( String name, String content ) {
- if( entityMap.get( name ) == null ) entityMap.put( name, content );
- }
-
- /** Method for adding new entities to their map. Obeys the rule that
- * entity, once defined, can not be overriden */
- void addPublicEntity( String name, String identifier, String file ) throws WrongDTDException {
- if( entityMap.get( name ) == null ) {
- StringBuffer sb = new StringBuffer();
- char[] buffer = new char[16384];
- Reader r = getReader( identifier, file );
- try {
- int len;
- while( (len = r.read( buffer )) >= 0 ) {
- sb.append( buffer, 0, len );
- }
- } catch( IOException e ) {
- throw new WrongDTDException( "Error reading included public entity " + name + " - " + e.getMessage() ); // NOI18N
- }
-
- entityMap.put( name, sb.toString() );
- }
- }
-
- DTD.Value createValue( String name ) {
- return new ValueImpl( (String)stringCache.put( name ) );
- }
-
- /** Creates new or lookups old ContentModel with given properites */
- DTD.ContentModel createContentModel( DTD.Content content, Set included, Set excluded ) {
-
- DTD.ContentModel cm = new ContentModelImpl( content, included, excluded );
- return (DTD.ContentModel)models.put( cm );
- }
- /** Creates new or lookups old ContentLeaf with given properites */
- DTD.Content createContentLeaf( String name ) {
- DTD.Content c = new ContentLeafImpl( name );
- c = (DTD.Content)contents.put( c );
- leafs.add( c ); // remember for final fixup
- return c;
- }
- /** Creates new or lookups old ContentNode with given properites */
- DTD.Content createContentNode( char type, DTD.Content subContent ) {
- return (DTD.Content)contents.put( new UnaryContentNodeImpl( type, subContent ) );
- }
- /** Creates new or lookups old ContentNode with given properites */
- DTD.Content createContentNode( char type, DTD.Content[] subContent ) {
- return (DTD.Content)contents.put( new MultiContentNodeImpl( type, subContent ) );
- }
- DTD.Element createElement( String name, DTD.ContentModel cm, boolean optStart, boolean optEnd, boolean xmlDTD) {
- DTD.Element retVal = new ElementImpl( name, cm, optStart, optEnd, new TreeMap(), xmlDTD );
- return retVal;
- }
-
- /** Creates new or lookups old attribute with given properites */
- DTD.Attribute createAttribute( String name, int type, String baseType, String typeHelper, String defaultMode, SortedMap values, boolean xmlDTD ) {
- DTD.Attribute attr = new AttributeImpl( name, type,
- (String)stringCache.put( baseType ),
- (String)stringCache.put( typeHelper ),
- (String)stringCache.put( defaultMode ),
- values, xmlDTD
- );
- return (DTD.Attribute)attributes.put( attr );
- }
-
- /** Adds given instance of DTD.Attribute to Element named elemName */
- void addAttrToElement( String elemName, DTD.Attribute attr) throws WrongDTDException {
- String key = xmlDTD ? elemName : elemName.toUpperCase(Locale.ENGLISH);
- ElementImpl elem = (ElementImpl)elementMap.get( key );
- if( elem == null ) throw new WrongDTDException( "Attribute definition for unknown Element \"" + elemName +"\"." ); // NOI18N
- elem.addAttribute( attr );
- }
-
- void createAddCharRef( String name, char value ) {
- DTD.CharRef ref = new CharRefImpl( name, value );
- charRefs.put( name, ref );
- }
- private boolean isNameChar( char c ) {
- return Character.isLetterOrDigit( c ) || c == '_' || c == '-' || c == '.' || c == ':';
- }
-
-
- /*----------------------------------------------------------------------------*/
- /*----------------------------- Parsing routines ---------------------------- */
- /*----------------------------------------------------------------------------*/
- private static final int DTD_INIT = 0;
- private static final int DTD_LT = 1; // after '<'
- private static final int DTD_EXC = 2; // after "<!"
- private static final int DTD_MINUS = 3; // after "<!-"
- private static final int DTD_ACOMMENT = 4; // after comment was parsed, awaiting '>'
-
- private void parseDTD( PushbackReader in ) throws IOException, WrongDTDException {
- int state = DTD_INIT;
- for( ;; ) {
- int i = in.read();
- if( i == -1 ) {
- break;
- }
- switch( state ) {
- case DTD_INIT:
- switch( i ) {
- case '<':
- state = DTD_LT;
- break;
- case '%':
- parseEntityReference( in );
- break; // Stay in DTD_INIT
- }
- break;
-
- case DTD_LT:
- if( i != '!' ) throw new WrongDTDException( "Unexpected char '" + (char)i + "' after '<'" ); // NOI18N
- state = DTD_EXC;
- break;
-
- case DTD_EXC:
- switch( i ) {
- case '-':
- state = DTD_MINUS;
- break;
- case '[':
- parseOptional( in );
- state = DTD_INIT;
- break;
- default:
- in.unread( i );
- parseMarkup( in );
- state = DTD_INIT;
- break;
- }
- break;
-
- case DTD_MINUS:
- if( i != '-' ) throw new WrongDTDException( "Unexpected char '" + (char)i + "' after \"<!-\"" ); // NOI18N
- parseComment( in );
- state = DTD_ACOMMENT;
- break;
-
- case DTD_ACOMMENT:
- if( i != '>' ) throw new WrongDTDException( "Unexpected char '" + (char)i + "' after comment" ); // NOI18N
- state = DTD_INIT;
- break;
-
- }
- }
- if( state != DTD_INIT ) throw new WrongDTDException( "Premature end of DTD" ); // NOI18N
- }
-
- /** Parser that reads the markup type after <!. Recognizes ENTITY, ELEMENT
- * and ATTLIST markup and forwards their processing to proper parser.
- * It gets the control just after starting "<!" and releases after eating
- * final '>' */
- private void parseMarkup( PushbackReader in ) throws IOException, WrongDTDException {
- StringBuffer sb = new StringBuffer();
- for( ;; ) {
- int i = in.read();
- if( i == -1 ) throw new WrongDTDException( "Premature end of DTD" ); // NOI18N EOF
- if( i == ' ' ) break;
- sb.append( (char)i ); // next char of name
- }
-
- String markup = sb.toString();
-
- if( "ENTITY".equals( markup ) ) { // NOI18N
- parseEntityDefinition( in );
- } else if( "ELEMENT".equals( markup ) ) { // NOI18N
- parseElement( in );
- } else if( "ATTLIST".equals( markup ) ) { // NOI18N
- parseAttlist( in );
- } else throw new WrongDTDException( "Wrong DTD markup <!" + markup ); // NOI18N
- }
-
-
- private static final int PED_INIT = 0;
- private static final int PED_PERCENT = 1;
- private static final int PED_CHAR = 2;
- private static final int PED_NAME = 3;
- private static final int PED_ANAME = 4;
- private static final int PED_VAL = 5;
- private static final int PED_TYPE = 6;
- private static final int PED_AVAL = 7;
- private static final int PED_AVAL_M = 8;
- private static final int PED_ATYPE = 9;
- private static final int PED_ID = 10;
- private static final int PED_AID = 11;
- private static final int PED_FILE = 12;
- private static final int PED_AFILE = 13;
- private static final int PED_AFILE_M = 14;
- private static final int PED_ACHAR = 15;
- private static final int PED_CH_TYPE = 16;
- private static final int PED_CH_ATYPE = 17;
- private static final int PED_CH_QUOT = 18;
-
-
- /* TODO: Parsing fo character references */
- private void parseEntityDefinition( PushbackReader in ) throws IOException, WrongDTDException {
- int state = PED_INIT;
- StringBuffer name = new StringBuffer();
- StringBuffer value = new StringBuffer();
- StringBuffer type = new StringBuffer();
- StringBuffer identifier = new StringBuffer();
-
- for( ;; ) {
- int i = in.read();
- if( i == -1 ) throw new WrongDTDException( "Premature end of DTD" ); // NOI18N EOF
- switch( state ) {
- case PED_INIT:
- if( Character.isWhitespace( (char)i ) ) break;
- if( i == '%' ) state = PED_PERCENT;
- else {
- name.append( (char)i );
- state = PED_CHAR;
- }
- break;
-
- case PED_PERCENT:
- if( Character.isWhitespace( (char)i ) ) break;
- name.append( (char)i );
- state = PED_NAME;
- break;
-
- case PED_NAME:
- if( Character.isWhitespace( (char)i ) ) {
- state = PED_ANAME;
- } else {
- name.append( (char)i );
- }
- break;
-
- case PED_ANAME:
- if( Character.isWhitespace( (char)i ) ) break;
- if( i == '"' ) state = PED_VAL;
- else {
- in.unread( i );
- state = PED_TYPE;
- }
- break;
-
- case PED_VAL:
- if( i == '"' ) {
- addEntity( name.toString(), value.toString() );
- state = PED_AVAL;
- } else {
- value.append( (char)i );
- }
- break;
-
- case PED_AVAL:
- if( i == '>' ) {
- return;
- }
- if( i == '-' ) state = PED_AVAL_M;
- break;
-
- case PED_AVAL_M:
- if( i == '-' ) parseComment( in );
- state = PED_AVAL;
- break;
-
- case PED_TYPE:
- if( Character.isWhitespace( (char)i ) ) {
- if( type.toString().equals( "PUBLIC" ) ) { // NOI18N
- state = PED_ATYPE;
- } else {
- throw new WrongDTDException( "Unexpected entity type \"" + type + "\"." ); // NOI18N
- }
- } else {
- type.append( (char)i );
- }
- break;
-
- case PED_ATYPE:
- if( Character.isWhitespace( (char)i ) ) break;
- if( i == '"' ) {
- state = PED_ID;
- break;
- }
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in PUBLIC entity." ); // NOI18N
-
- case PED_ID:
- if( i == '"' ) {
- state = PED_AID;
- } else {
- identifier.append( (char)i );
- }
- break;
-
- case PED_AID:
- if( Character.isWhitespace( (char)i ) ) break;
- if( i == '"' ) {
- state = PED_FILE;
- break;
- }
- if( i == '>' ) {
- addPublicEntity( name.toString(), identifier.toString(), null );
- return;
- }
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in PUBLIC entity." ); // NOI18N
-
- case PED_FILE:
- if( i == '"' ) {
- state = PED_AFILE;
- } else {
- value.append( (char)i );
- }
- break;
-
- case PED_AFILE:
- if( Character.isWhitespace( (char)i ) ) break;
- if( i == '-' ) {
- state = PED_AFILE_M;
- break;
- }
- if( i == '>' ) {
- addPublicEntity( name.toString(), identifier.toString(), value.toString() );
- return;
- }
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in PUBLIC entity." ); // NOI18N
-
- case PED_AFILE_M:
- if( i == '-' ) {
- parseComment( in );
- state = PED_FILE;
- break;
- }
- throw new WrongDTDException( "Unexpected sequence \"-" + (char)i + "\" in in PUBLIC entity." ); // NOI18N
-
- case PED_CHAR:
- if( Character.isWhitespace( (char)i ) ) {
- state = PED_ACHAR;
- } else {
- name.append( (char)i );
- }
- break;
-
- case PED_ACHAR:
- if( Character.isWhitespace( (char)i ) ) break;
- else {
- //name read
- if(xmlDTD) {
- in.unread(i); //backup the char
- type.append("CDATA");
- state = PED_CH_ATYPE;
- break; //reread i
- } else {
- type.append( (char)i );
- state = PED_CH_TYPE;
- }
- }
- break;
-
- case PED_CH_TYPE:
- if( Character.isWhitespace( (char)i ) ) {
- if( type.toString().equals( "CDATA" ) ) { // NOI18N
- state = PED_CH_ATYPE;
- } else {
- throw new WrongDTDException( "Unexpected entity type \"" + type + "\"." ); // NOI18N
- }
- } else {
- type.append( (char)i );
- }
- break;
-
- case PED_CH_ATYPE:
- if( Character.isWhitespace( (char)i ) ) break;
- else if( i == '"' ) {
- state = PED_CH_QUOT;
- } else {
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in entity." ); // NOI18N
- }
- break;
-
- case PED_CH_QUOT:
- if( i == '"' ) {
- if(xmlDTD) {
- //resolve '&' char reference
- String replaced = value.toString().replace("&", "&");
- value.replace(0, value.length(), replaced);
- }
- value.delete( 0, 2 );
- value.deleteCharAt( value.length() - 1 );
- int code = Integer.parseInt( value.toString() );
- createAddCharRef( name.toString(), (char)code );
- state = PED_AVAL;
- } else {
- value.append( (char)i );
- }
- }
-
- }
- }
-
- private static final int GR_INIT=0;
- private static final int GR_NAME=1;
- private static final int GR_ANAME=2;
- /** Parse group of names separated by '|' character and optional spaces
- * @return List of Strings containing names */
- private List parseGroup( PushbackReader in ) throws IOException, WrongDTDException {
- int state = GR_INIT;
- StringBuffer name = new StringBuffer();
- List list = new ArrayList();
-
- for( ;; ) {
- int i = in.read();
- if( i == -1 ) throw new WrongDTDException( "Premature end of DTD" ); // NOI18N EOF
- switch( state ) {
- case GR_INIT:
- if( Character.isWhitespace( (char)i ) ) break;
- if( i == '%' ) {
- parseEntityReference( in );
- } else {
- name.append( (char)i );
- state = GR_NAME;
- }
- break;
-
- case GR_NAME:
- if( isNameChar( (char)i ) ) {
- name.append( (char)i );
- break;
- }
- switch( i ) {
- case ')':
- list.add( name.toString() );
- return list;
- case '|':
- list.add( name.toString() );
- name.setLength( 0 );
- state = GR_INIT;
- break;
- default:
- if( Character.isWhitespace( (char)i ) ) {
- list.add( name.toString() );
- name.setLength( 0 );
- state = GR_ANAME;
- break;
- } else {
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in group definition." ); // NOI18N
- }
- }
- break;
-
- case GR_ANAME:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case ')':
- return list;
- case '|':
- state = GR_INIT;
- break;
- default:
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in group definition." ); // NOI18N
- }
- break;
- }
- }
-
- }
-
- private static final int EL_INIT = 0;
- private static final int EL_NAME = 1;
- private static final int EL_ANAME = 2;
- private static final int EL_ASTART = 3;
- private static final int EL_ACONTENT = 4;
- private static final int EL_PLUS = 5;
- private static final int EL_MINUS = 6;
- private static final int EL_ANAME_XML = 7;
-
- /** parse the whole element(s) definition including content model.
- * Create corresponding instances of DTD.Element filled with proper
- * informations. Make the same content models and their contents shared
- * across the DTD */
- private void parseElement( PushbackReader in ) throws IOException, WrongDTDException {
- int state = EL_INIT;
- StringBuffer name = new StringBuffer();
- List list = null;
- boolean optStart = false;
- boolean optEnd = false;
- DTD.Content content = null;
- Set inSet = new HashSet();
- Set exSet = new HashSet();
-
- for( ;; ) {
- int i = in.read();
- if( i == -1 ) break;
- switch( state ) {
- case EL_INIT:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case '(':
- list = parseGroup( in );
- state = EL_ANAME;
- break;
- case '%':
- parseEntityReference( in );
- break; // Stay in EL_INIT
- default:
- name.append( (char)i );
- state = EL_NAME;
- break;
- }
- break;
-
- case EL_NAME:
- if( Character.isWhitespace( (char)i ) ) {
- state = xmlDTD ? EL_ANAME_XML : EL_ANAME;
- list = new ArrayList();
- list.add( name.toString() );
- } else {
- name.append( (char)i );
- }
- break;
- case EL_ANAME_XML:
- if( Character.isWhitespace( (char)i ) ) break;
- in.unread(i); //backup
- content = parseContent( in );
- //optStart = false; optEnd = false; //default
- state = EL_ACONTENT;
- break;
- case EL_ANAME:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case 'O':
- optStart = true; // fall fhrough
- case '-':
- state = EL_ASTART;
- break;
- default:
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in ELEMENT optStart definition." ); // NOI18N
- }
- break;
- case EL_ASTART:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case 'O':
- optEnd = true; // fall fhrough
- case '-':
- content = parseContent( in );
- state = EL_ACONTENT;
- break;
- default:
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in ELEMENT optEnd definition." ); // NOI18N
- }
- break;
-
- case EL_ACONTENT:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case '+':
- state = EL_PLUS;
- break;
- case '-':
- state = EL_MINUS;
- break;
- case '>':
- DTD.ContentModel cm = createContentModel( content, inSet, exSet );
- for( Iterator iter = list.iterator(); iter.hasNext(); ) {
- String key = (String)iter.next();
- key = xmlDTD ? key : key.toUpperCase(Locale.ENGLISH);
- elementMap.put( key, createElement( key, cm, optStart, optEnd, xmlDTD) );
- }
- return;
- default:
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in ELEMENT definition." ); // NOI18N
- }
- break;
-
- case EL_PLUS:
- if( i == '(' ) {
- state = EL_ACONTENT;
- inSet.addAll( parseGroup( in ) );
- } else {
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in ELEMENT definition." ); // NOI18N
- }
- break;
-
- case EL_MINUS:
- switch( i ) {
- case '(':
- state = EL_ACONTENT;
- List l = parseGroup( in );
- exSet.addAll( l );
- break;
- case '-':
- state = EL_ACONTENT;
- parseComment( in );
- break;
- default:
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in ELEMENT definition." ); // NOI18N
- }
- break;
- }
- }
- //XXX
- }
-
- private static final int CO_INIT = 0;
- private static final int CO_NAME = 1;
- private static final int CO_AMODEL = 2;
- private static final int CO_AND = 3;
- private static final int CO_OR = 4;
- private static final int CO_SEQ = 5;
- private static final int CO_AGROUP = 6;
- /** This automata would parse content model definitions and return them
- * as a Content instance of root of generated CM tree */
- private DTD.Content parseContent( PushbackReader in ) throws IOException, WrongDTDException {
- int state = EL_INIT;
- StringBuffer name = new StringBuffer();
- ArrayList list = null;
- DTD.Content content = null;
-
- for( ;; ) {
- int i = in.read();
- if( i == -1 ) break;
- switch( state ) {
- case CO_INIT:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case '%':
- parseEntityReference( in );
- break; // Stay in CO_INIT
- case '(':
- content = parseContent( in );
- state = CO_AMODEL;
- break;
- default:
- name.append( (char)i );
- state = CO_NAME;
- break;
- }
- break;
-
- case CO_NAME:
- if( isNameChar( (char)i ) ) {
- name.append( (char)i );
- } else {
- switch( i ) {
- case '?':
- case '+':
- case '*':
- DTD.Content leaf = createContentLeaf( name.toString() );
- return createContentNode( (char)i, leaf );
- default:
- in.unread( i );
- return createContentLeaf( name.toString() );
- }
- }
- break;
- case CO_AMODEL:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case '&':
- list = new ArrayList();
- list.add( content );
- list.add( parseContent( in ) );
- state = CO_AND;
- break;
- case '|':
- list = new ArrayList();
- list.add( content );
- list.add( parseContent( in ) );
- state = CO_OR;
- break;
- case ',':
- list = new ArrayList();
- list.add( content );
- list.add( parseContent( in ) );
- state = CO_SEQ;
- break;
- case ')':
- state = CO_AGROUP;
- break;
- default:
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in ELEMENT optEnd definition." ); // NOI18N
- }
- break;
-
- case CO_AND:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case '&':
- list.add( parseContent( in ) );
- break;
- case ')':
- content = createContentNode( '&', (DTD.Content[])list.toArray( new DTD.Content[0] ) );
- state = CO_AGROUP;
- break;
- default:
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in ContentModel definition." ); // NOI18N
- }
- break;
- case CO_OR:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case '|':
- list.add( parseContent( in ) );
- break;
- case ')':
- content = createContentNode( '|', (DTD.Content[])list.toArray( new DTD.Content[0] ) );
- state = CO_AGROUP;
- break;
- default:
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in ContentModel definition." ); // NOI18N
- }
- break;
-
- case CO_SEQ:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case ',':
- list.add( parseContent( in ) );
- break;
- case ')':
- content = createContentNode( ',', (DTD.Content[])list.toArray( new DTD.Content[0] ) );
- state = CO_AGROUP;
- break;
- default:
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in ContentModel definition." ); // NOI18N
- }
- break;
- case CO_AGROUP:
- if( Character.isWhitespace( (char)i ) ) return content;
- switch( i ) {
- case '?':
- case '+':
- case '*':
- return createContentNode( (char)i, content );
- default:
- in.unread( i );
- return content;
- }
- }
- }
-
- throw new WrongDTDException( "Premature end of DTD" ); // NOI18N EOF
- }
- private static final int ATT_INIT = 0;
- private static final int ATT_NAME = 1;
- private static final int ATT_ANAME = 2;
- private static final int ATT_ANAME_M = 3;
- private static final int ATT_VAR = 4;
- private static final int ATT_AVAR = 5;
- private static final int ATT_TYPE = 6;
- private static final int ATT_ATYPE = 7;
- private static final int ATT_MODE = 8;
- private static final int ATT_FIXED_VALUE = 9;
- private static final int ATT_FIXED_VALUE_SQ = 10;
- private static final int ATT_FIXED_VALUE_DQ = 11;
- private void parseAttlist( PushbackReader in ) throws IOException, WrongDTDException {
- int state = ATT_INIT;
- StringBuffer name = new StringBuffer();
- List list = null; // List of tag names for which are these attribs
- StringBuffer attr = new StringBuffer(); // name of attribute
- List values = null; // (list of possible values
- StringBuffer type = new StringBuffer(); // OR the type of attribute )
- String typeHelper = null; // AND name of entity
- StringBuffer mode = new StringBuffer(); // default mode of this attrib
- for( ;; ) {
- int i = in.read();
- if( i == -1 ) break;
- switch( state ) {
- case ATT_INIT:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case '%':
- parseEntityReference( in );
- break; // Stay in ATT_INIT
- case '(':
- list = parseGroup( in );
- state = ATT_ANAME;
- break;
- default:
- name.append( (char)i );
- state = ATT_NAME;
- break;
- }
- break;
-
- case ATT_NAME:
- if( Character.isWhitespace( (char)i ) ) {
- list = new ArrayList();
- list.add( name.toString() );
- state = ATT_ANAME;
- break;
- }
- name.append( (char)i );
- break;
-
- case ATT_ANAME:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case '%':
- parseEntityReference( in );
- break; // Stay in ATT_ANAME
- case '-':
- state = ATT_ANAME_M;
- break;
- case '>':
- return;
- default:
- attr.append( (char)i );
- state = ATT_VAR;
- break;
- }
- break;
-
- case ATT_ANAME_M:
- if( i == '-' ) {
- parseComment( in ); // skip the comment
- state = ATT_ANAME;
- } else {
- throw new WrongDTDException( "Unexpected char '" + (char)i + "' in ATTLIST definition." ); // NOI18N
- }
- break;
-
- case ATT_VAR:
- if( Character.isWhitespace( (char)i ) ) {
- state = ATT_AVAR;
- break;
- }
- attr.append( (char)i );
- break;
-
- case ATT_AVAR:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case '%':
- typeHelper = parseEntityReference( in );
- break; // Stay in ATT_AVAR
- case '(':
- values = parseGroup( in );
- state = ATT_ATYPE;
- break;
- default:
- type.append( (char)i );
- state = ATT_TYPE;
- break;
- }
- break;
- case ATT_TYPE:
- if( Character.isWhitespace( (char)i ) ) {
- state = ATT_ATYPE;
- break;
- }
- type.append( (char)i );
- break;
-
- case ATT_ATYPE:
- if( Character.isWhitespace( (char)i ) ) break;
- switch( i ) {
- case '%':
- parseEntityReference( in );
- break; // Stay in ATT_ATYPE
- default:
- mode.append( (char)i );
- state = ATT_MODE;
- break;
- }
- break;
-
- case ATT_MODE:
- if( Character.isWhitespace( (char)i ) || i == '>') {
- // Create attr and add it to all tags
- DTD.Attribute a = null;
-
- if( values == null ) { // HOTSPOT for internation of strings!!!
- a = createAttribute( attr.toString(),
- DTD.Attribute.TYPE_BASE, type.toString(),
- typeHelper, mode.toString(), null, xmlDTD );
- } else if( values.size() == 1 ) {
- a = createAttribute( attr.toString(),
- DTD.Attribute.TYPE_BOOLEAN, null, typeHelper,
- mode.toString(), null, xmlDTD );
- } else {
- SortedMap vals = new TreeMap();
- for( Iterator iter = values.iterator(); iter.hasNext(); ) {
- String key = (String)iter.next();
- String valName = xmlDTD ? key : key.toLowerCase(Locale.ENGLISH);
- vals.put( valName, createValue( valName ) );
- }
- a = createAttribute( attr.toString(),
- DTD.Attribute.TYPE_SET, null, typeHelper,
- mode.toString(), vals, xmlDTD );
- }
- for( Iterator iter = list.iterator(); iter.hasNext(); ) {
- addAttrToElement( (String)iter.next(), a );
- }
-
- typeHelper = null;
- attr.setLength(0);
- type.setLength(0);
- mode.setLength(0);
- values = null;
- if(xmlDTD && a.getDefaultMode().equals(DTD.Attribute.MODE_FIXED)) {
- //skip the fixed value
- state = ATT_FIXED_VALUE;
- } else {
- state = ATT_ANAME;
- }
- if(i == '>') {
- return ;
- }
- break;
- }
- mode.append( (char)i );
- break;
- case ATT_FIXED_VALUE:
- if( Character.isWhitespace( (char)i ) ) break;
- if(i == '\'') {
- state = ATT_FIXED_VALUE_SQ;
- } else if(i == '"') {
- state = ATT_FIXED_VALUE_DQ;
- }
- break;
- case ATT_FIXED_VALUE_SQ:
- if(i == '\'') {
- state = ATT_ANAME;
- break;
- }
- break;
- case ATT_FIXED_VALUE_DQ:
- if(i == '"') {
- state = ATT_ANAME;
- break;
- }
- break;
- }
- }
- }
-
-
- private static final int OPT_INIT = 0;
- private static final int OPT_PROCESS = 1;
- private static final int OPT_APROCESS = 2;
- private static final int OPT_CONTENT = 3;
- private static final int OPT_BRAC1 = 4;
- private static final int OPT_BRAC2 = 5;
- /** Parser that takes care of conditional inclusion/exclusion of part
- * of DTD. Gets the control just after "<![" */
- private void parseOptional( PushbackReader in ) throws IOException, WrongDTDException {
- int state = OPT_INIT;
- StringBuffer process = new StringBuffer();
- StringBuffer content = new StringBuffer();
- boolean ignore = false;
-
- for( ;; ) {
- int i = in.read();
- if( i == -1 ) break; // EOF
- switch( state ) {
- case OPT_INIT:
- if( Character.isWhitespace( (char)i ) ) break;
- if( i == '%' ) {
- parseEntityReference( in );
- break;
- }
- process.append( (char)i );
- state = OPT_PROCESS;
- break;
-
- case OPT_PROCESS:
- if( Character.isWhitespace( (char)i ) ) {
- String s = process.toString();
- if( "IGNORE".equals( s ) ) ignore = true; // NOI18N
- else if( ! "INCLUDE".equals( s ) ) throw new WrongDTDException( "Unexpected processing instruction " + s ); // NOI18N
- state = OPT_APROCESS;
- } else {
- process.append( (char)i );
- }
- break;
-
- case OPT_APROCESS:
- if( Character.isWhitespace( (char)i ) ) break;
- if( i == '[' ) state = OPT_CONTENT;
- else throw new WrongDTDException( "Unexpected char '" + (char)i + "' in processing instruction." ); // NOI18N
- break;
-
- case OPT_CONTENT:
- if( i == ']' ) state = OPT_BRAC1;
- else content.append( (char)i );
- break;
-
- case OPT_BRAC1:
- if( i == ']' ) state = OPT_BRAC2;
- else {
- content.append( ']' ).append( (char)i );
- state = OPT_CONTENT;
- }
- break;
-
- case OPT_BRAC2:
- if( Character.isWhitespace( (char)i ) ) break;
- if( i == '>' ) {
-