mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			5435 lines
		
	
	
		
			155 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			5435 lines
		
	
	
		
			155 KiB
		
	
	
	
		
			Java
		
	
	
	
/* XMLParser.java --
 | 
						|
   Copyright (C) 2005  Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version.
 | 
						|
 | 
						|
Partly derived from code which carried the following notice:
 | 
						|
 | 
						|
  Copyright (c) 1997, 1998 by Microstar Software Ltd.
 | 
						|
 | 
						|
  AElfred is free for both commercial and non-commercial use and
 | 
						|
  redistribution, provided that Microstar's copyright and disclaimer are
 | 
						|
  retained intact.  You are free to modify AElfred for your own use and
 | 
						|
  to redistribute AElfred with your modifications, provided that the
 | 
						|
  modifications are clearly documented.
 | 
						|
 | 
						|
  This program is distributed in the hope that it will be useful, but
 | 
						|
  WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
  merchantability or fitness for a particular purpose.  Please use it AT
 | 
						|
  YOUR OWN RISK.
 | 
						|
*/
 | 
						|
 | 
						|
package gnu.xml.stream;
 | 
						|
 | 
						|
import gnu.java.lang.CPStringBuilder;
 | 
						|
 | 
						|
import java.io.BufferedInputStream;
 | 
						|
import java.io.EOFException;
 | 
						|
import java.io.File;
 | 
						|
import java.io.FileOutputStream;
 | 
						|
import java.io.FileWriter;
 | 
						|
import java.io.InputStream;
 | 
						|
import java.io.InputStreamReader;
 | 
						|
import java.io.IOException;
 | 
						|
import java.io.Reader;
 | 
						|
import java.io.StringReader;
 | 
						|
import java.io.UnsupportedEncodingException;
 | 
						|
import java.net.MalformedURLException;
 | 
						|
import java.net.URL;
 | 
						|
import java.util.ArrayList;
 | 
						|
import java.util.Collections;
 | 
						|
import java.util.HashSet;
 | 
						|
import java.util.Iterator;
 | 
						|
import java.util.LinkedHashMap;
 | 
						|
import java.util.LinkedList;
 | 
						|
import java.util.Map;
 | 
						|
import java.util.NoSuchElementException;
 | 
						|
import java.util.StringTokenizer;
 | 
						|
 | 
						|
import javax.xml.XMLConstants;
 | 
						|
import javax.xml.namespace.NamespaceContext;
 | 
						|
import javax.xml.namespace.QName;
 | 
						|
import javax.xml.stream.Location;
 | 
						|
import javax.xml.stream.XMLInputFactory;
 | 
						|
import javax.xml.stream.XMLReporter;
 | 
						|
import javax.xml.stream.XMLResolver;
 | 
						|
import javax.xml.stream.XMLStreamConstants;
 | 
						|
import javax.xml.stream.XMLStreamException;
 | 
						|
import javax.xml.stream.XMLStreamReader;
 | 
						|
 | 
						|
import gnu.java.net.CRLFInputStream;
 | 
						|
import gnu.classpath.debug.TeeInputStream;
 | 
						|
import gnu.classpath.debug.TeeReader;
 | 
						|
 | 
						|
/**
 | 
						|
 * An XML parser.
 | 
						|
 * This parser supports the following additional StAX properties:
 | 
						|
 * <table>
 | 
						|
 * <tr><td>gnu.xml.stream.stringInterning</td>
 | 
						|
 * <td>Boolean</td>
 | 
						|
 * <td>Indicates whether markup strings will be interned</td></tr>
 | 
						|
 * <tr><td>gnu.xml.stream.xmlBase</td>
 | 
						|
 * <td>Boolean</td>
 | 
						|
 * <td>Indicates whether XML Base processing will be performed</td></tr>
 | 
						|
 * <tr><td>gnu.xml.stream.baseURI</td>
 | 
						|
 * <td>String</td>
 | 
						|
 * <td>Returns the base URI of the current event</td></tr>
 | 
						|
 * </table>
 | 
						|
 *
 | 
						|
 * @see http://www.w3.org/TR/REC-xml/
 | 
						|
 * @see http://www.w3.org/TR/xml11/
 | 
						|
 * @see http://www.w3.org/TR/REC-xml-names
 | 
						|
 * @see http://www.w3.org/TR/xml-names11
 | 
						|
 * @see http://www.w3.org/TR/xmlbase/
 | 
						|
 *
 | 
						|
 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
 | 
						|
 */
 | 
						|
public class XMLParser
 | 
						|
  implements XMLStreamReader, NamespaceContext
 | 
						|
{
 | 
						|
 | 
						|
  // -- parser state machine states --
 | 
						|
  private static final int INIT = 0; // start state
 | 
						|
  private static final int PROLOG = 1; // in prolog
 | 
						|
  private static final int CONTENT = 2; // in content
 | 
						|
  private static final int EMPTY_ELEMENT = 3; // empty element state
 | 
						|
  private static final int MISC = 4; // in Misc (after root element)
 | 
						|
 | 
						|
  // -- parameters for parsing literals --
 | 
						|
  private final static int LIT_ENTITY_REF = 2;
 | 
						|
  private final static int LIT_NORMALIZE = 4;
 | 
						|
  private final static int LIT_ATTRIBUTE = 8;
 | 
						|
  private final static int LIT_DISABLE_PE = 16;
 | 
						|
  private final static int LIT_DISABLE_CREF = 32;
 | 
						|
  private final static int LIT_DISABLE_EREF = 64;
 | 
						|
  private final static int LIT_PUBID = 256;
 | 
						|
 | 
						|
  // -- types of attribute values --
 | 
						|
  final static int ATTRIBUTE_DEFAULT_UNDECLARED = 30;
 | 
						|
  final static int ATTRIBUTE_DEFAULT_SPECIFIED = 31;
 | 
						|
  final static int ATTRIBUTE_DEFAULT_IMPLIED = 32;
 | 
						|
  final static int ATTRIBUTE_DEFAULT_REQUIRED = 33;
 | 
						|
  final static int ATTRIBUTE_DEFAULT_FIXED = 34;
 | 
						|
 | 
						|
  // -- additional event types --
 | 
						|
  final static int START_ENTITY = 50;
 | 
						|
  final static int END_ENTITY = 51;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The current input.
 | 
						|
   */
 | 
						|
  private Input input;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Stack of inputs representing XML general entities.
 | 
						|
   * The input representing the XML input stream or reader is always the
 | 
						|
   * first element in this stack.
 | 
						|
   */
 | 
						|
  private LinkedList inputStack = new LinkedList();
 | 
						|
 | 
						|
  /**
 | 
						|
   * Stack of start-entity events to be reported.
 | 
						|
   */
 | 
						|
  private LinkedList startEntityStack = new LinkedList();
 | 
						|
 | 
						|
  /**
 | 
						|
   * Stack of end-entity events to be reported.
 | 
						|
   */
 | 
						|
  private LinkedList endEntityStack = new LinkedList();
 | 
						|
 | 
						|
  /**
 | 
						|
   * Current parser state within the main state machine.
 | 
						|
   */
 | 
						|
  private int state = INIT;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The (type of the) current event.
 | 
						|
   */
 | 
						|
  private int event;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The element name stack. The first element in this stack will be the
 | 
						|
   * root element.
 | 
						|
   */
 | 
						|
  private LinkedList stack = new LinkedList();
 | 
						|
 | 
						|
  /**
 | 
						|
   * Stack of namespace contexts. These are maps specifying prefix-to-URI
 | 
						|
   * mappings. The first element in this stack is the most recent namespace
 | 
						|
   * context (i.e. the other way around from the element name stack).
 | 
						|
   */
 | 
						|
  private LinkedList namespaces = new LinkedList();
 | 
						|
 | 
						|
  /**
 | 
						|
   * The base-URI stack. This holds the base URI context for each element.
 | 
						|
   * The first element in this stack is the most recent context (i.e. the
 | 
						|
   * other way around from the element name stack).
 | 
						|
   */
 | 
						|
  private LinkedList bases = new LinkedList();
 | 
						|
 | 
						|
  /**
 | 
						|
   * The list of attributes for the current element, in the order defined in
 | 
						|
   * the XML stream.
 | 
						|
   */
 | 
						|
  private ArrayList attrs = new ArrayList();
 | 
						|
 | 
						|
  /**
 | 
						|
   * Buffer for text and character data.
 | 
						|
   */
 | 
						|
  private StringBuffer buf = new StringBuffer();
 | 
						|
 | 
						|
  /**
 | 
						|
   * Buffer for NMTOKEN strings (markup).
 | 
						|
   */
 | 
						|
  private StringBuffer nmtokenBuf = new StringBuffer();
 | 
						|
 | 
						|
  /**
 | 
						|
   * Buffer for string literals. (e.g. attribute values)
 | 
						|
   */
 | 
						|
  private StringBuffer literalBuf = new StringBuffer();
 | 
						|
 | 
						|
  /**
 | 
						|
   * Temporary Unicode character buffer used during character data reads.
 | 
						|
   */
 | 
						|
  private int[] tmpBuf = new int[1024];
 | 
						|
 | 
						|
  /**
 | 
						|
   * The element content model for the current element.
 | 
						|
   */
 | 
						|
  private ContentModel currentContentModel;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The validation stack. This holds lists of the elements seen for each
 | 
						|
   * element, in order to determine whether the names and order of these
 | 
						|
   * elements match the content model for the element. The last entry in
 | 
						|
   * this stack represents the current element.
 | 
						|
   */
 | 
						|
  private LinkedList validationStack;
 | 
						|
 | 
						|
  /**
 | 
						|
   * These sets contain the IDs and the IDREFs seen in the document, to
 | 
						|
   * ensure that IDs are unique and that each IDREF refers to an ID in the
 | 
						|
   * document.
 | 
						|
   */
 | 
						|
  private HashSet ids, idrefs;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The target and data associated with the current processing instruction
 | 
						|
   * event.
 | 
						|
   */
 | 
						|
  private String piTarget, piData;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The XML version declared in the XML declaration.
 | 
						|
   */
 | 
						|
  private String xmlVersion;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The encoding declared in the XML declaration.
 | 
						|
   */
 | 
						|
  private String xmlEncoding;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The standalone value declared in the XML declaration.
 | 
						|
   */
 | 
						|
  private Boolean xmlStandalone;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The document type definition.
 | 
						|
   */
 | 
						|
  Doctype doctype;
 | 
						|
 | 
						|
  /**
 | 
						|
   * State variables for determining parameter-entity expansion.
 | 
						|
   */
 | 
						|
  private boolean expandPE, peIsError;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Whether this is a validating parser.
 | 
						|
   */
 | 
						|
  private final boolean validating;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Whether strings representing markup will be interned.
 | 
						|
   */
 | 
						|
  private final boolean stringInterning;
 | 
						|
 | 
						|
  /**
 | 
						|
   * If true, CDATA sections will be merged with adjacent text nodes into a
 | 
						|
   * single event.
 | 
						|
   */
 | 
						|
  private final boolean coalescing;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Whether to replace general entity references with their replacement
 | 
						|
   * text automatically during parsing.
 | 
						|
   * Otherwise entity-reference events will be issued.
 | 
						|
   */
 | 
						|
  private final boolean replaceERefs;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Whether to support external entities.
 | 
						|
   */
 | 
						|
  private final boolean externalEntities;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Whether to support DTDs.
 | 
						|
   */
 | 
						|
  private final boolean supportDTD;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Whether to support XML namespaces. If true, namespace information will
 | 
						|
   * be available. Otherwise namespaces will simply be reported as ordinary
 | 
						|
   * attributes.
 | 
						|
   */
 | 
						|
  private final boolean namespaceAware;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Whether to support XML Base. If true, URIs specified in xml:base
 | 
						|
   * attributes will be honoured when resolving external entities.
 | 
						|
   */
 | 
						|
  private final boolean baseAware;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Whether to report extended event types (START_ENTITY and END_ENTITY)
 | 
						|
   * in addition to the standard event types. Used by the SAX parser.
 | 
						|
   */
 | 
						|
  private final boolean extendedEventTypes;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The reporter to receive parsing warnings.
 | 
						|
   */
 | 
						|
  final XMLReporter reporter;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Callback interface for resolving external entities.
 | 
						|
   */
 | 
						|
  final XMLResolver resolver;
 | 
						|
 | 
						|
  // -- Constants for testing the next kind of markup event --
 | 
						|
  private static final String TEST_START_ELEMENT = "<";
 | 
						|
  private static final String TEST_END_ELEMENT = "</";
 | 
						|
  private static final String TEST_COMMENT = "<!--";
 | 
						|
  private static final String TEST_PI = "<?";
 | 
						|
  private static final String TEST_CDATA = "<![CDATA[";
 | 
						|
  private static final String TEST_XML_DECL = "<?xml";
 | 
						|
  private static final String TEST_DOCTYPE_DECL = "<!DOCTYPE";
 | 
						|
  private static final String TEST_ELEMENT_DECL = "<!ELEMENT";
 | 
						|
  private static final String TEST_ATTLIST_DECL = "<!ATTLIST";
 | 
						|
  private static final String TEST_ENTITY_DECL = "<!ENTITY";
 | 
						|
  private static final String TEST_NOTATION_DECL = "<!NOTATION";
 | 
						|
  private static final String TEST_KET = ">";
 | 
						|
  private static final String TEST_END_COMMENT = "--";
 | 
						|
  private static final String TEST_END_PI = "?>";
 | 
						|
  private static final String TEST_END_CDATA = "]]>";
 | 
						|
 | 
						|
  /**
 | 
						|
   * The general entities predefined by the XML specification.
 | 
						|
   */
 | 
						|
  private static final LinkedHashMap PREDEFINED_ENTITIES = new LinkedHashMap();
 | 
						|
  static
 | 
						|
  {
 | 
						|
    PREDEFINED_ENTITIES.put("amp", "&");
 | 
						|
    PREDEFINED_ENTITIES.put("lt", "<");
 | 
						|
    PREDEFINED_ENTITIES.put("gt", ">");
 | 
						|
    PREDEFINED_ENTITIES.put("apos", "'");
 | 
						|
    PREDEFINED_ENTITIES.put("quot", "\"");
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates a new XML parser for the given input stream.
 | 
						|
   * This constructor should be used where possible, as it allows the
 | 
						|
   * encoding of the XML data to be correctly determined from the stream.
 | 
						|
   * @param in the input stream
 | 
						|
   * @param systemId the URL from which the input stream was retrieved
 | 
						|
   * (necessary if there are external entities to be resolved)
 | 
						|
   * @param validating if the parser is to be a validating parser
 | 
						|
   * @param namespaceAware if the parser should support XML Namespaces
 | 
						|
   * @param coalescing if CDATA sections should be merged into adjacent text
 | 
						|
   * nodes
 | 
						|
   * @param replaceERefs if entity references should be automatically
 | 
						|
   * replaced by their replacement text (otherwise they will be reported as
 | 
						|
   * entity-reference events)
 | 
						|
   * @param externalEntities if external entities should be loaded
 | 
						|
   * @param supportDTD if support for the XML DTD should be enabled
 | 
						|
   * @param baseAware if the parser should support XML Base to resolve
 | 
						|
   * external entities
 | 
						|
   * @param stringInterning whether strings will be interned during parsing
 | 
						|
   * @param reporter the reporter to receive warnings during processing
 | 
						|
   * @param resolver the callback interface used to resolve external
 | 
						|
   * entities
 | 
						|
   */
 | 
						|
  public XMLParser(InputStream in, String systemId,
 | 
						|
                   boolean validating,
 | 
						|
                   boolean namespaceAware,
 | 
						|
                   boolean coalescing,
 | 
						|
                   boolean replaceERefs,
 | 
						|
                   boolean externalEntities,
 | 
						|
                   boolean supportDTD,
 | 
						|
                   boolean baseAware,
 | 
						|
                   boolean stringInterning,
 | 
						|
                   boolean extendedEventTypes,
 | 
						|
                   XMLReporter reporter,
 | 
						|
                   XMLResolver resolver)
 | 
						|
  {
 | 
						|
    this.validating = validating;
 | 
						|
    this.namespaceAware = namespaceAware;
 | 
						|
    this.coalescing = coalescing;
 | 
						|
    this.replaceERefs = replaceERefs;
 | 
						|
    this.externalEntities = externalEntities;
 | 
						|
    this.supportDTD = supportDTD;
 | 
						|
    this.baseAware = baseAware;
 | 
						|
    this.stringInterning = stringInterning;
 | 
						|
    this.extendedEventTypes = extendedEventTypes;
 | 
						|
    this.reporter = reporter;
 | 
						|
    this.resolver = resolver;
 | 
						|
    if (validating)
 | 
						|
      {
 | 
						|
        validationStack = new LinkedList();
 | 
						|
        ids = new HashSet();
 | 
						|
        idrefs = new HashSet();
 | 
						|
      }
 | 
						|
    String debug = System.getProperty("gnu.xml.debug.input");
 | 
						|
    if (debug != null)
 | 
						|
      {
 | 
						|
        try
 | 
						|
          {
 | 
						|
            File file = File.createTempFile(debug, ".xml");
 | 
						|
            in = new TeeInputStream(in, new FileOutputStream(file));
 | 
						|
          }
 | 
						|
        catch (IOException e)
 | 
						|
          {
 | 
						|
            RuntimeException e2 = new RuntimeException();
 | 
						|
            e2.initCause(e);
 | 
						|
            throw e2;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    systemId = canonicalize(systemId);
 | 
						|
    pushInput(new Input(in, null, null, systemId, null, null, false, true));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates a new XML parser for the given character stream.
 | 
						|
   * This constructor is only available for compatibility with the JAXP
 | 
						|
   * APIs, which permit XML to be parsed from a character stream. Because
 | 
						|
   * the encoding specified by the character stream may conflict with that
 | 
						|
   * specified in the XML declaration, this method should be avoided where
 | 
						|
   * possible.
 | 
						|
   * @param in the input stream
 | 
						|
   * @param systemId the URL from which the input stream was retrieved
 | 
						|
   * (necessary if there are external entities to be resolved)
 | 
						|
   * @param validating if the parser is to be a validating parser
 | 
						|
   * @param namespaceAware if the parser should support XML Namespaces
 | 
						|
   * @param coalescing if CDATA sections should be merged into adjacent text
 | 
						|
   * nodes
 | 
						|
   * @param replaceERefs if entity references should be automatically
 | 
						|
   * replaced by their replacement text (otherwise they will be reported as
 | 
						|
   * entity-reference events)
 | 
						|
   * @param externalEntities if external entities should be loaded
 | 
						|
   * @param supportDTD if support for the XML DTD should be enabled
 | 
						|
   * @param baseAware if the parser should support XML Base to resolve
 | 
						|
   * external entities
 | 
						|
   * @param stringInterning whether strings will be interned during parsing
 | 
						|
   * @param reporter the reporter to receive warnings during processing
 | 
						|
   * @param resolver the callback interface used to resolve external
 | 
						|
   * entities
 | 
						|
   */
 | 
						|
  public XMLParser(Reader reader, String systemId,
 | 
						|
                   boolean validating,
 | 
						|
                   boolean namespaceAware,
 | 
						|
                   boolean coalescing,
 | 
						|
                   boolean replaceERefs,
 | 
						|
                   boolean externalEntities,
 | 
						|
                   boolean supportDTD,
 | 
						|
                   boolean baseAware,
 | 
						|
                   boolean stringInterning,
 | 
						|
                   boolean extendedEventTypes,
 | 
						|
                   XMLReporter reporter,
 | 
						|
                   XMLResolver resolver)
 | 
						|
  {
 | 
						|
    this.validating = validating;
 | 
						|
    this.namespaceAware = namespaceAware;
 | 
						|
    this.coalescing = coalescing;
 | 
						|
    this.replaceERefs = replaceERefs;
 | 
						|
    this.externalEntities = externalEntities;
 | 
						|
    this.supportDTD = supportDTD;
 | 
						|
    this.baseAware = baseAware;
 | 
						|
    this.stringInterning = stringInterning;
 | 
						|
    this.extendedEventTypes = extendedEventTypes;
 | 
						|
    this.reporter = reporter;
 | 
						|
    this.resolver = resolver;
 | 
						|
    if (validating)
 | 
						|
      {
 | 
						|
        validationStack = new LinkedList();
 | 
						|
        ids = new HashSet();
 | 
						|
        idrefs = new HashSet();
 | 
						|
      }
 | 
						|
    String debug = System.getProperty("gnu.xml.debug.input");
 | 
						|
    if (debug != null)
 | 
						|
      {
 | 
						|
        try
 | 
						|
          {
 | 
						|
            File file = File.createTempFile(debug, ".xml");
 | 
						|
            reader = new TeeReader(reader, new FileWriter(file));
 | 
						|
          }
 | 
						|
        catch (IOException e)
 | 
						|
          {
 | 
						|
            RuntimeException e2 = new RuntimeException();
 | 
						|
            e2.initCause(e);
 | 
						|
            throw e2;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    systemId = canonicalize(systemId);
 | 
						|
    pushInput(new Input(null, reader, null, systemId, null, null, false, true));
 | 
						|
  }
 | 
						|
 | 
						|
  // -- NamespaceContext --
 | 
						|
 | 
						|
  public String getNamespaceURI(String prefix)
 | 
						|
  {
 | 
						|
    if (XMLConstants.XML_NS_PREFIX.equals(prefix))
 | 
						|
      return XMLConstants.XML_NS_URI;
 | 
						|
    if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
 | 
						|
      return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
 | 
						|
    for (Iterator i = namespaces.iterator(); i.hasNext(); )
 | 
						|
      {
 | 
						|
        LinkedHashMap ctx = (LinkedHashMap) i.next();
 | 
						|
        String namespaceURI = (String) ctx.get(prefix);
 | 
						|
        if (namespaceURI != null)
 | 
						|
          return namespaceURI;
 | 
						|
      }
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  public String getPrefix(String namespaceURI)
 | 
						|
  {
 | 
						|
    if (XMLConstants.XML_NS_URI.equals(namespaceURI))
 | 
						|
      return XMLConstants.XML_NS_PREFIX;
 | 
						|
    if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI))
 | 
						|
      return XMLConstants.XMLNS_ATTRIBUTE;
 | 
						|
    for (Iterator i = namespaces.iterator(); i.hasNext(); )
 | 
						|
      {
 | 
						|
        LinkedHashMap ctx = (LinkedHashMap) i.next();
 | 
						|
        if (ctx.containsValue(namespaceURI))
 | 
						|
          {
 | 
						|
            for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); )
 | 
						|
              {
 | 
						|
                Map.Entry entry = (Map.Entry) i.next();
 | 
						|
                String uri = (String) entry.getValue();
 | 
						|
                if (uri.equals(namespaceURI))
 | 
						|
                  return (String) entry.getKey();
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  public Iterator getPrefixes(String namespaceURI)
 | 
						|
  {
 | 
						|
    if (XMLConstants.XML_NS_URI.equals(namespaceURI))
 | 
						|
      return Collections.singleton(XMLConstants.XML_NS_PREFIX).iterator();
 | 
						|
    if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI))
 | 
						|
      return Collections.singleton(XMLConstants.XMLNS_ATTRIBUTE).iterator();
 | 
						|
    LinkedList acc = new LinkedList();
 | 
						|
    for (Iterator i = namespaces.iterator(); i.hasNext(); )
 | 
						|
      {
 | 
						|
        LinkedHashMap ctx = (LinkedHashMap) i.next();
 | 
						|
        if (ctx.containsValue(namespaceURI))
 | 
						|
          {
 | 
						|
            for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); )
 | 
						|
              {
 | 
						|
                Map.Entry entry = (Map.Entry) i.next();
 | 
						|
                String uri = (String) entry.getValue();
 | 
						|
                if (uri.equals(namespaceURI))
 | 
						|
                  acc.add(entry.getKey());
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return acc.iterator();
 | 
						|
  }
 | 
						|
 | 
						|
  // -- XMLStreamReader --
 | 
						|
 | 
						|
  public void close()
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    stack = null;
 | 
						|
    namespaces = null;
 | 
						|
    bases = null;
 | 
						|
    buf = null;
 | 
						|
    attrs = null;
 | 
						|
    doctype = null;
 | 
						|
 | 
						|
    inputStack = null;
 | 
						|
    validationStack = null;
 | 
						|
    ids = null;
 | 
						|
    idrefs = null;
 | 
						|
  }
 | 
						|
 | 
						|
  public NamespaceContext getNamespaceContext()
 | 
						|
  {
 | 
						|
    return this;
 | 
						|
  }
 | 
						|
 | 
						|
  public int getAttributeCount()
 | 
						|
  {
 | 
						|
    return attrs.size();
 | 
						|
  }
 | 
						|
 | 
						|
  public String getAttributeLocalName(int index)
 | 
						|
  {
 | 
						|
    Attribute a = (Attribute) attrs.get(index);
 | 
						|
    return a.localName;
 | 
						|
  }
 | 
						|
 | 
						|
  public String getAttributeNamespace(int index)
 | 
						|
  {
 | 
						|
    String prefix = getAttributePrefix(index);
 | 
						|
    return getNamespaceURI(prefix);
 | 
						|
  }
 | 
						|
 | 
						|
  public String getAttributePrefix(int index)
 | 
						|
  {
 | 
						|
    Attribute a = (Attribute) attrs.get(index);
 | 
						|
    return a.prefix;
 | 
						|
  }
 | 
						|
 | 
						|
  public QName getAttributeName(int index)
 | 
						|
  {
 | 
						|
    Attribute a = (Attribute) attrs.get(index);
 | 
						|
    String namespaceURI = getNamespaceURI(a.prefix);
 | 
						|
    return new QName(namespaceURI, a.localName, a.prefix);
 | 
						|
  }
 | 
						|
 | 
						|
  public String getAttributeType(int index)
 | 
						|
  {
 | 
						|
    Attribute a = (Attribute) attrs.get(index);
 | 
						|
    return a.type;
 | 
						|
  }
 | 
						|
 | 
						|
  private String getAttributeType(String elementName, String attName)
 | 
						|
  {
 | 
						|
    if (doctype != null)
 | 
						|
      {
 | 
						|
        AttributeDecl att = doctype.getAttributeDecl(elementName, attName);
 | 
						|
        if (att != null)
 | 
						|
          return att.type;
 | 
						|
      }
 | 
						|
    return "CDATA";
 | 
						|
  }
 | 
						|
 | 
						|
  public String getAttributeValue(int index)
 | 
						|
  {
 | 
						|
    Attribute a = (Attribute) attrs.get(index);
 | 
						|
    return a.value;
 | 
						|
  }
 | 
						|
 | 
						|
  public String getAttributeValue(String namespaceURI, String localName)
 | 
						|
  {
 | 
						|
    for (Iterator i = attrs.iterator(); i.hasNext(); )
 | 
						|
      {
 | 
						|
        Attribute a = (Attribute) i.next();
 | 
						|
        if (a.localName.equals(localName))
 | 
						|
          {
 | 
						|
            String uri = getNamespaceURI(a.prefix);
 | 
						|
            if ((uri == null && namespaceURI == null) ||
 | 
						|
                (uri != null && uri.equals(namespaceURI)))
 | 
						|
              return a.value;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  boolean isAttributeDeclared(int index)
 | 
						|
  {
 | 
						|
    if (doctype == null)
 | 
						|
      return false;
 | 
						|
    Attribute a = (Attribute) attrs.get(index);
 | 
						|
    String qn = ("".equals(a.prefix)) ? a.localName :
 | 
						|
      a.prefix + ":" + a.localName;
 | 
						|
    String elementName = buf.toString();
 | 
						|
    return doctype.isAttributeDeclared(elementName, qn);
 | 
						|
  }
 | 
						|
 | 
						|
  public String getCharacterEncodingScheme()
 | 
						|
  {
 | 
						|
    return xmlEncoding;
 | 
						|
  }
 | 
						|
 | 
						|
  public String getElementText()
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    if (event != XMLStreamConstants.START_ELEMENT)
 | 
						|
      throw new XMLStreamException("current event must be START_ELEMENT");
 | 
						|
    CPStringBuilder elementText = new CPStringBuilder();
 | 
						|
    int depth = stack.size();
 | 
						|
    while (event != XMLStreamConstants.END_ELEMENT || stack.size() > depth)
 | 
						|
      {
 | 
						|
        switch (next())
 | 
						|
          {
 | 
						|
          case XMLStreamConstants.CHARACTERS:
 | 
						|
          case XMLStreamConstants.SPACE:
 | 
						|
            elementText.append(buf.toString());
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return elementText.toString();
 | 
						|
  }
 | 
						|
 | 
						|
  public String getEncoding()
 | 
						|
  {
 | 
						|
    return (input.inputEncoding == null) ? "UTF-8" : input.inputEncoding;
 | 
						|
  }
 | 
						|
 | 
						|
  public int getEventType()
 | 
						|
  {
 | 
						|
    return event;
 | 
						|
  }
 | 
						|
 | 
						|
  public String getLocalName()
 | 
						|
  {
 | 
						|
    switch (event)
 | 
						|
      {
 | 
						|
      case XMLStreamConstants.START_ELEMENT:
 | 
						|
      case XMLStreamConstants.END_ELEMENT:
 | 
						|
        String qName = buf.toString();
 | 
						|
        int ci = qName.indexOf(':');
 | 
						|
        String localName = (ci == -1) ? qName : qName.substring(ci + 1);
 | 
						|
        if (stringInterning)
 | 
						|
          localName = localName.intern();
 | 
						|
        return localName;
 | 
						|
      default:
 | 
						|
        return null;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  public Location getLocation()
 | 
						|
  {
 | 
						|
    return input;
 | 
						|
  }
 | 
						|
 | 
						|
  public QName getName()
 | 
						|
  {
 | 
						|
    switch (event)
 | 
						|
      {
 | 
						|
      case XMLStreamConstants.START_ELEMENT:
 | 
						|
      case XMLStreamConstants.END_ELEMENT:
 | 
						|
        String qName = buf.toString();
 | 
						|
        int ci = qName.indexOf(':');
 | 
						|
        String localName = (ci == -1) ? qName : qName.substring(ci + 1);
 | 
						|
        if (stringInterning)
 | 
						|
          localName = localName.intern();
 | 
						|
        String prefix = (ci == -1) ?
 | 
						|
          (namespaceAware ? XMLConstants.DEFAULT_NS_PREFIX : null) :
 | 
						|
          qName.substring(0, ci);
 | 
						|
        if (stringInterning && prefix != null)
 | 
						|
          prefix = prefix.intern();
 | 
						|
        String namespaceURI = getNamespaceURI(prefix);
 | 
						|
        return new QName(namespaceURI, localName, prefix);
 | 
						|
      default:
 | 
						|
        return null;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  public int getNamespaceCount()
 | 
						|
  {
 | 
						|
    if (!namespaceAware || namespaces.isEmpty())
 | 
						|
      return 0;
 | 
						|
    switch (event)
 | 
						|
      {
 | 
						|
      case XMLStreamConstants.START_ELEMENT:
 | 
						|
      case XMLStreamConstants.END_ELEMENT:
 | 
						|
        LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
 | 
						|
        return ctx.size();
 | 
						|
      default:
 | 
						|
        return 0;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  public String getNamespacePrefix(int index)
 | 
						|
  {
 | 
						|
    LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
 | 
						|
    int count = 0;
 | 
						|
    for (Iterator i = ctx.keySet().iterator(); i.hasNext(); )
 | 
						|
      {
 | 
						|
        String prefix = (String) i.next();
 | 
						|
        if (count++ == index)
 | 
						|
          return prefix;
 | 
						|
      }
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  public String getNamespaceURI()
 | 
						|
  {
 | 
						|
    switch (event)
 | 
						|
      {
 | 
						|
      case XMLStreamConstants.START_ELEMENT:
 | 
						|
      case XMLStreamConstants.END_ELEMENT:
 | 
						|
        String qName = buf.toString();
 | 
						|
        int ci = qName.indexOf(':');
 | 
						|
        if (ci == -1)
 | 
						|
          return null;
 | 
						|
        String prefix = qName.substring(0, ci);
 | 
						|
        return getNamespaceURI(prefix);
 | 
						|
      default:
 | 
						|
        return null;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  public String getNamespaceURI(int index)
 | 
						|
  {
 | 
						|
    LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
 | 
						|
    int count = 0;
 | 
						|
    for (Iterator i = ctx.values().iterator(); i.hasNext(); )
 | 
						|
      {
 | 
						|
        String uri = (String) i.next();
 | 
						|
        if (count++ == index)
 | 
						|
          return uri;
 | 
						|
      }
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  public String getPIData()
 | 
						|
  {
 | 
						|
    return piData;
 | 
						|
  }
 | 
						|
 | 
						|
  public String getPITarget()
 | 
						|
  {
 | 
						|
    return piTarget;
 | 
						|
  }
 | 
						|
 | 
						|
  public String getPrefix()
 | 
						|
  {
 | 
						|
    switch (event)
 | 
						|
      {
 | 
						|
      case XMLStreamConstants.START_ELEMENT:
 | 
						|
      case XMLStreamConstants.END_ELEMENT:
 | 
						|
        String qName = buf.toString();
 | 
						|
        int ci = qName.indexOf(':');
 | 
						|
        String prefix = (ci == -1) ?
 | 
						|
          (namespaceAware ? XMLConstants.DEFAULT_NS_PREFIX : null) :
 | 
						|
          qName.substring(0, ci);
 | 
						|
        if (stringInterning && prefix != null)
 | 
						|
          prefix = prefix.intern();
 | 
						|
        return prefix;
 | 
						|
      default:
 | 
						|
        return null;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  public Object getProperty(String name)
 | 
						|
    throws IllegalArgumentException
 | 
						|
  {
 | 
						|
    if (name == null)
 | 
						|
      throw new IllegalArgumentException("name is null");
 | 
						|
    if (XMLInputFactory.ALLOCATOR.equals(name))
 | 
						|
      return null;
 | 
						|
    if (XMLInputFactory.IS_COALESCING.equals(name))
 | 
						|
      return coalescing ? Boolean.TRUE : Boolean.FALSE;
 | 
						|
    if (XMLInputFactory.IS_NAMESPACE_AWARE.equals(name))
 | 
						|
      return namespaceAware ? Boolean.TRUE : Boolean.FALSE;
 | 
						|
    if (XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES.equals(name))
 | 
						|
      return replaceERefs ? Boolean.TRUE : Boolean.FALSE;
 | 
						|
    if (XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES.equals(name))
 | 
						|
      return externalEntities ? Boolean.TRUE : Boolean.FALSE;
 | 
						|
    if (XMLInputFactory.IS_VALIDATING.equals(name))
 | 
						|
      return Boolean.FALSE;
 | 
						|
    if (XMLInputFactory.REPORTER.equals(name))
 | 
						|
      return reporter;
 | 
						|
    if (XMLInputFactory.RESOLVER.equals(name))
 | 
						|
      return resolver;
 | 
						|
    if (XMLInputFactory.SUPPORT_DTD.equals(name))
 | 
						|
      return supportDTD ? Boolean.TRUE : Boolean.FALSE;
 | 
						|
    if ("gnu.xml.stream.stringInterning".equals(name))
 | 
						|
      return stringInterning ? Boolean.TRUE : Boolean.FALSE;
 | 
						|
    if ("gnu.xml.stream.xmlBase".equals(name))
 | 
						|
      return baseAware ? Boolean.TRUE : Boolean.FALSE;
 | 
						|
    if ("gnu.xml.stream.baseURI".equals(name))
 | 
						|
      return getXMLBase();
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  public String getText()
 | 
						|
  {
 | 
						|
    return buf.toString();
 | 
						|
  }
 | 
						|
 | 
						|
  public char[] getTextCharacters()
 | 
						|
  {
 | 
						|
    return buf.toString().toCharArray();
 | 
						|
  }
 | 
						|
 | 
						|
  public int getTextCharacters(int sourceStart, char[] target,
 | 
						|
                               int targetStart, int length)
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    length = Math.min(sourceStart + buf.length(), length);
 | 
						|
    int sourceEnd = sourceStart + length;
 | 
						|
    buf.getChars(sourceStart, sourceEnd, target, targetStart);
 | 
						|
    return length;
 | 
						|
  }
 | 
						|
 | 
						|
  public int getTextLength()
 | 
						|
  {
 | 
						|
    return buf.length();
 | 
						|
  }
 | 
						|
 | 
						|
  public int getTextStart()
 | 
						|
  {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  public String getVersion()
 | 
						|
  {
 | 
						|
    return (xmlVersion == null) ? "1.0" : xmlVersion;
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean hasName()
 | 
						|
  {
 | 
						|
    switch (event)
 | 
						|
      {
 | 
						|
      case XMLStreamConstants.START_ELEMENT:
 | 
						|
      case XMLStreamConstants.END_ELEMENT:
 | 
						|
        return true;
 | 
						|
      default:
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean hasText()
 | 
						|
  {
 | 
						|
    switch (event)
 | 
						|
      {
 | 
						|
      case XMLStreamConstants.CHARACTERS:
 | 
						|
      case XMLStreamConstants.SPACE:
 | 
						|
        return true;
 | 
						|
      default:
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean isAttributeSpecified(int index)
 | 
						|
  {
 | 
						|
    Attribute a = (Attribute) attrs.get(index);
 | 
						|
    return a.specified;
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean isCharacters()
 | 
						|
  {
 | 
						|
    return (event == XMLStreamConstants.CHARACTERS);
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean isEndElement()
 | 
						|
  {
 | 
						|
    return (event == XMLStreamConstants.END_ELEMENT);
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean isStandalone()
 | 
						|
  {
 | 
						|
    return Boolean.TRUE.equals(xmlStandalone);
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean isStartElement()
 | 
						|
  {
 | 
						|
    return (event == XMLStreamConstants.START_ELEMENT);
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean isWhiteSpace()
 | 
						|
  {
 | 
						|
    return (event == XMLStreamConstants.SPACE);
 | 
						|
  }
 | 
						|
 | 
						|
  public int nextTag()
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    do
 | 
						|
      {
 | 
						|
        switch (next())
 | 
						|
          {
 | 
						|
          case XMLStreamConstants.START_ELEMENT:
 | 
						|
          case XMLStreamConstants.END_ELEMENT:
 | 
						|
          case XMLStreamConstants.CHARACTERS:
 | 
						|
          case XMLStreamConstants.SPACE:
 | 
						|
          case XMLStreamConstants.COMMENT:
 | 
						|
          case XMLStreamConstants.PROCESSING_INSTRUCTION:
 | 
						|
            break;
 | 
						|
          default:
 | 
						|
            throw new XMLStreamException("Unexpected event type: " + event);
 | 
						|
          }
 | 
						|
      }
 | 
						|
    while (event != XMLStreamConstants.START_ELEMENT &&
 | 
						|
           event != XMLStreamConstants.END_ELEMENT);
 | 
						|
    return event;
 | 
						|
  }
 | 
						|
 | 
						|
  public void require(int type, String namespaceURI, String localName)
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    if (event != type)
 | 
						|
      throw new XMLStreamException("Current event type is " + event);
 | 
						|
    if (event == XMLStreamConstants.START_ELEMENT ||
 | 
						|
        event == XMLStreamConstants.END_ELEMENT)
 | 
						|
      {
 | 
						|
        String ln = getLocalName();
 | 
						|
        if (!ln.equals(localName))
 | 
						|
          throw new XMLStreamException("Current local-name is " + ln);
 | 
						|
        String uri = getNamespaceURI();
 | 
						|
        if ((uri == null && namespaceURI != null) ||
 | 
						|
            (uri != null && !uri.equals(namespaceURI)))
 | 
						|
          throw new XMLStreamException("Current namespace URI is " + uri);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean standaloneSet()
 | 
						|
  {
 | 
						|
    return (xmlStandalone != null);
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean hasNext()
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    return (event != XMLStreamConstants.END_DOCUMENT && event != -1);
 | 
						|
  }
 | 
						|
 | 
						|
  public int next()
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    if (event == XMLStreamConstants.END_ELEMENT)
 | 
						|
      {
 | 
						|
        // Pop namespace context
 | 
						|
        if (namespaceAware && !namespaces.isEmpty())
 | 
						|
          namespaces.removeFirst();
 | 
						|
        // Pop base context
 | 
						|
        if (baseAware && !bases.isEmpty())
 | 
						|
          bases.removeFirst();
 | 
						|
      }
 | 
						|
    if (!startEntityStack.isEmpty())
 | 
						|
      {
 | 
						|
        String entityName = (String) startEntityStack.removeFirst();
 | 
						|
        buf.setLength(0);
 | 
						|
        buf.append(entityName);
 | 
						|
        event = START_ENTITY;
 | 
						|
        return extendedEventTypes ? event : next();
 | 
						|
      }
 | 
						|
    else if (!endEntityStack.isEmpty())
 | 
						|
      {
 | 
						|
        String entityName = (String) endEntityStack.removeFirst();
 | 
						|
        buf.setLength(0);
 | 
						|
        buf.append(entityName);
 | 
						|
        event = END_ENTITY;
 | 
						|
        return extendedEventTypes ? event : next();
 | 
						|
      }
 | 
						|
    try
 | 
						|
      {
 | 
						|
        if (!input.initialized)
 | 
						|
          input.init();
 | 
						|
        switch (state)
 | 
						|
          {
 | 
						|
          case CONTENT:
 | 
						|
            if (tryRead(TEST_END_ELEMENT))
 | 
						|
              {
 | 
						|
                readEndElement();
 | 
						|
                if (stack.isEmpty())
 | 
						|
                  state = MISC;
 | 
						|
                event = XMLStreamConstants.END_ELEMENT;
 | 
						|
              }
 | 
						|
            else if (tryRead(TEST_COMMENT))
 | 
						|
              {
 | 
						|
                readComment(false);
 | 
						|
                event = XMLStreamConstants.COMMENT;
 | 
						|
              }
 | 
						|
            else if (tryRead(TEST_PI))
 | 
						|
              {
 | 
						|
                readPI(false);
 | 
						|
                event = XMLStreamConstants.PROCESSING_INSTRUCTION;
 | 
						|
              }
 | 
						|
            else if (tryRead(TEST_CDATA))
 | 
						|
              {
 | 
						|
                readCDSect();
 | 
						|
                event = XMLStreamConstants.CDATA;
 | 
						|
              }
 | 
						|
            else if (tryRead(TEST_START_ELEMENT))
 | 
						|
              {
 | 
						|
                state = readStartElement();
 | 
						|
                event = XMLStreamConstants.START_ELEMENT;
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                // Check for character reference or predefined entity
 | 
						|
                mark(8);
 | 
						|
                int c = readCh();
 | 
						|
                if (c == 0x26) // '&'
 | 
						|
                  {
 | 
						|
                    c = readCh();
 | 
						|
                    if (c == 0x23) // '#'
 | 
						|
                      {
 | 
						|
                        reset();
 | 
						|
                        event = readCharData(null);
 | 
						|
                      }
 | 
						|
                    else
 | 
						|
                      {
 | 
						|
                        // entity reference
 | 
						|
                        reset();
 | 
						|
                        readCh(); // &
 | 
						|
                        readReference();
 | 
						|
                        String ref = buf.toString();
 | 
						|
                        String text = (String) PREDEFINED_ENTITIES.get(ref);
 | 
						|
                        if (text != null)
 | 
						|
                          {
 | 
						|
                            event = readCharData(text);
 | 
						|
                          }
 | 
						|
                        else if (replaceERefs && !isUnparsedEntity(ref))
 | 
						|
                          {
 | 
						|
                            // this will report a start-entity event
 | 
						|
                            boolean external = false;
 | 
						|
                            if (doctype != null)
 | 
						|
                              {
 | 
						|
                                Object entity = doctype.getEntity(ref);
 | 
						|
                                if (entity instanceof ExternalIds)
 | 
						|
                                  external = true;
 | 
						|
                              }
 | 
						|
                            expandEntity(ref, false, external);
 | 
						|
                            event = next();
 | 
						|
                          }
 | 
						|
                        else
 | 
						|
                          {
 | 
						|
                            event = XMLStreamConstants.ENTITY_REFERENCE;
 | 
						|
                          }
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  {
 | 
						|
                    reset();
 | 
						|
                    event = readCharData(null);
 | 
						|
                    if (validating && doctype != null)
 | 
						|
                      validatePCData(buf.toString());
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            break;
 | 
						|
          case EMPTY_ELEMENT:
 | 
						|
            String elementName = (String) stack.removeLast();
 | 
						|
            buf.setLength(0);
 | 
						|
            buf.append(elementName);
 | 
						|
            state = stack.isEmpty() ? MISC : CONTENT;
 | 
						|
            event = XMLStreamConstants.END_ELEMENT;
 | 
						|
            if (validating && doctype != null)
 | 
						|
              endElementValidationHook();
 | 
						|
            break;
 | 
						|
          case INIT: // XMLDecl?
 | 
						|
            if (tryRead(TEST_XML_DECL))
 | 
						|
              readXMLDecl();
 | 
						|
            input.finalizeEncoding();
 | 
						|
            event = XMLStreamConstants.START_DOCUMENT;
 | 
						|
            state = PROLOG;
 | 
						|
            break;
 | 
						|
          case PROLOG: // Misc* (doctypedecl Misc*)?
 | 
						|
            skipWhitespace();
 | 
						|
            if (doctype == null && tryRead(TEST_DOCTYPE_DECL))
 | 
						|
              {
 | 
						|
                readDoctypeDecl();
 | 
						|
                event = XMLStreamConstants.DTD;
 | 
						|
              }
 | 
						|
            else if (tryRead(TEST_COMMENT))
 | 
						|
              {
 | 
						|
                readComment(false);
 | 
						|
                event = XMLStreamConstants.COMMENT;
 | 
						|
              }
 | 
						|
            else if (tryRead(TEST_PI))
 | 
						|
              {
 | 
						|
                readPI(false);
 | 
						|
                event = XMLStreamConstants.PROCESSING_INSTRUCTION;
 | 
						|
              }
 | 
						|
            else if (tryRead(TEST_START_ELEMENT))
 | 
						|
              {
 | 
						|
                state = readStartElement();
 | 
						|
                event = XMLStreamConstants.START_ELEMENT;
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                int c = readCh();
 | 
						|
                error("no root element: U+" + Integer.toHexString(c));
 | 
						|
              }
 | 
						|
            break;
 | 
						|
          case MISC: // Comment | PI | S
 | 
						|
            skipWhitespace();
 | 
						|
            if (tryRead(TEST_COMMENT))
 | 
						|
              {
 | 
						|
                readComment(false);
 | 
						|
                event = XMLStreamConstants.COMMENT;
 | 
						|
              }
 | 
						|
            else if (tryRead(TEST_PI))
 | 
						|
              {
 | 
						|
                readPI(false);
 | 
						|
                event = XMLStreamConstants.PROCESSING_INSTRUCTION;
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                if (event == XMLStreamConstants.END_DOCUMENT)
 | 
						|
                  throw new NoSuchElementException();
 | 
						|
                int c = readCh();
 | 
						|
                if (c != -1)
 | 
						|
                  error("Only comments and PIs may appear after " +
 | 
						|
                        "the root element");
 | 
						|
                event = XMLStreamConstants.END_DOCUMENT;
 | 
						|
              }
 | 
						|
            break;
 | 
						|
          default:
 | 
						|
            event = -1;
 | 
						|
          }
 | 
						|
        return event;
 | 
						|
      }
 | 
						|
    catch (IOException e)
 | 
						|
      {
 | 
						|
        XMLStreamException e2 = new XMLStreamException();
 | 
						|
        e2.initCause(e);
 | 
						|
        throw e2;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  // package private
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the current element name.
 | 
						|
   */
 | 
						|
  String getCurrentElement()
 | 
						|
  {
 | 
						|
    return (String) stack.getLast();
 | 
						|
  }
 | 
						|
 | 
						|
  // private
 | 
						|
 | 
						|
  private void mark(int limit)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    input.mark(limit);
 | 
						|
  }
 | 
						|
 | 
						|
  private void reset()
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    input.reset();
 | 
						|
  }
 | 
						|
 | 
						|
  private int read()
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    return input.read();
 | 
						|
  }
 | 
						|
 | 
						|
  private int read(int[] b, int off, int len)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    return input.read(b, off, len);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parsed character read.
 | 
						|
   */
 | 
						|
  private int readCh()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    int c = read();
 | 
						|
    if (expandPE && c == 0x25) // '%'
 | 
						|
      {
 | 
						|
        if (peIsError)
 | 
						|
          error("PE reference within decl in internal subset.");
 | 
						|
        expandPEReference();
 | 
						|
        return readCh();
 | 
						|
      }
 | 
						|
    return c;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Reads the next character, ensuring it is the character specified.
 | 
						|
   * @param delim the character to match
 | 
						|
   * @exception XMLStreamException if the next character is not the
 | 
						|
   * specified one
 | 
						|
   */
 | 
						|
  private void require(char delim)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    mark(1);
 | 
						|
    int c = readCh();
 | 
						|
    if (delim != c)
 | 
						|
      {
 | 
						|
        reset();
 | 
						|
        error("required character (got U+" + Integer.toHexString(c) + ")",
 | 
						|
              new Character(delim));
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Reads the next few characters, ensuring they match the string specified.
 | 
						|
   * @param delim the string to match
 | 
						|
   * @exception XMLStreamException if the next characters do not match the
 | 
						|
   * specified string
 | 
						|
   */
 | 
						|
  private void require(String delim)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    char[] chars = delim.toCharArray();
 | 
						|
    int len = chars.length;
 | 
						|
    mark(len);
 | 
						|
    int off = 0;
 | 
						|
    do
 | 
						|
      {
 | 
						|
        int l2 = read(tmpBuf, off, len - off);
 | 
						|
        if (l2 == -1)
 | 
						|
          {
 | 
						|
            reset();
 | 
						|
            error("EOF before required string", delim);
 | 
						|
          }
 | 
						|
        off += l2;
 | 
						|
      }
 | 
						|
    while (off < len);
 | 
						|
    for (int i = 0; i < chars.length; i++)
 | 
						|
      {
 | 
						|
        if (chars[i] != tmpBuf[i])
 | 
						|
          {
 | 
						|
            reset();
 | 
						|
            error("required string", delim);
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Try to read a single character. On failure, reset the stream.
 | 
						|
   * @param delim the character to test
 | 
						|
   * @return true if the character matched delim, false otherwise.
 | 
						|
   */
 | 
						|
  private boolean tryRead(char delim)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    mark(1);
 | 
						|
    int c = readCh();
 | 
						|
    if (delim != c)
 | 
						|
      {
 | 
						|
        reset();
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Tries to read the specified characters.
 | 
						|
   * If successful, the stream is positioned after the last character,
 | 
						|
   * otherwise it is reset.
 | 
						|
   * @param test the string to test
 | 
						|
   * @return true if the characters matched the test string, false otherwise.
 | 
						|
   */
 | 
						|
  private boolean tryRead(String test)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    char[] chars = test.toCharArray();
 | 
						|
    int len = chars.length;
 | 
						|
    mark(len);
 | 
						|
    int count = 0;
 | 
						|
    int l2 = read(tmpBuf, 0, len);
 | 
						|
    if (l2 == -1)
 | 
						|
      {
 | 
						|
        reset();
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
    count += l2;
 | 
						|
    // check the characters we received first before doing additional reads
 | 
						|
    for (int i = 0; i < count; i++)
 | 
						|
      {
 | 
						|
        if (chars[i] != tmpBuf[i])
 | 
						|
          {
 | 
						|
            reset();
 | 
						|
            return false;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    while (count < len)
 | 
						|
      {
 | 
						|
        // force read
 | 
						|
        int c = read();
 | 
						|
        if (c == -1)
 | 
						|
          {
 | 
						|
            reset();
 | 
						|
            return false;
 | 
						|
          }
 | 
						|
        tmpBuf[count] = (char) c;
 | 
						|
        // check each character as it is read
 | 
						|
        if (chars[count] != tmpBuf[count])
 | 
						|
          {
 | 
						|
            reset();
 | 
						|
            return false;
 | 
						|
          }
 | 
						|
        count++;
 | 
						|
      }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Reads characters until the specified test string is encountered.
 | 
						|
   * @param delim the string delimiting the end of the characters
 | 
						|
   */
 | 
						|
  private void readUntil(String delim)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    int startLine = input.line;
 | 
						|
    try
 | 
						|
      {
 | 
						|
        while (!tryRead(delim))
 | 
						|
          {
 | 
						|
            int c = readCh();
 | 
						|
            if (c == -1)
 | 
						|
              throw new EOFException();
 | 
						|
            else if (input.xml11)
 | 
						|
              {
 | 
						|
                if (!isXML11Char(c) || isXML11RestrictedChar(c))
 | 
						|
                  error("illegal XML 1.1 character",
 | 
						|
                        "U+" + Integer.toHexString(c));
 | 
						|
              }
 | 
						|
            else if (!isChar(c))
 | 
						|
              error("illegal XML character",
 | 
						|
                    "U+" + Integer.toHexString(c));
 | 
						|
            buf.append(Character.toChars(c));
 | 
						|
          }
 | 
						|
      }
 | 
						|
    catch (EOFException e)
 | 
						|
      {
 | 
						|
        error("end of input while looking for delimiter "+
 | 
						|
              "(started on line " + startLine + ')', delim);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Reads any whitespace characters.
 | 
						|
   * @return true if whitespace characters were read, false otherwise
 | 
						|
   */
 | 
						|
  private boolean tryWhitespace()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    boolean white;
 | 
						|
    boolean ret = false;
 | 
						|
    do
 | 
						|
      {
 | 
						|
        mark(1);
 | 
						|
        int c = readCh();
 | 
						|
        while (c == -1 && inputStack.size() > 1)
 | 
						|
          {
 | 
						|
            popInput();
 | 
						|
            c = readCh();
 | 
						|
          }
 | 
						|
        white = (c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d);
 | 
						|
        if (white)
 | 
						|
          ret = true;
 | 
						|
      }
 | 
						|
    while (white);
 | 
						|
    reset();
 | 
						|
    return ret;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Skip over any whitespace characters.
 | 
						|
   */
 | 
						|
  private void skipWhitespace()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    boolean white;
 | 
						|
    do
 | 
						|
      {
 | 
						|
        mark(1);
 | 
						|
        int c = readCh();
 | 
						|
        while (c == -1 && inputStack.size() > 1)
 | 
						|
          {
 | 
						|
            popInput();
 | 
						|
            c = readCh();
 | 
						|
          }
 | 
						|
        white = (c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d);
 | 
						|
      }
 | 
						|
    while (white);
 | 
						|
    reset();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Try to read as many whitespace characters as are available.
 | 
						|
   * @exception XMLStreamException if no whitespace characters were seen
 | 
						|
   */
 | 
						|
  private void requireWhitespace()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    if (!tryWhitespace())
 | 
						|
      error("whitespace required");
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the current base URI for resolving external entities.
 | 
						|
   */
 | 
						|
  String getXMLBase()
 | 
						|
  {
 | 
						|
    if (baseAware)
 | 
						|
      {
 | 
						|
        for (Iterator i = bases.iterator(); i.hasNext(); )
 | 
						|
          {
 | 
						|
            String base = (String) i.next();
 | 
						|
            if (base != null)
 | 
						|
              return base;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return input.systemId;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Push the specified text input source.
 | 
						|
   */
 | 
						|
  private void pushInput(String name, String text, boolean report,
 | 
						|
                         boolean normalize)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    // Check for recursion
 | 
						|
    if (name != null && !"".equals(name))
 | 
						|
      {
 | 
						|
        for (Iterator i = inputStack.iterator(); i.hasNext(); )
 | 
						|
          {
 | 
						|
            Input ctx = (Input) i.next();
 | 
						|
            if (name.equals(ctx.name))
 | 
						|
              error("entities may not be self-recursive", name);
 | 
						|
          }
 | 
						|
      }
 | 
						|
    else
 | 
						|
      report = false;
 | 
						|
    pushInput(new Input(null, new StringReader(text), input.publicId,
 | 
						|
                        input.systemId, name, input.inputEncoding, report,
 | 
						|
                        normalize));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Push the specified external input source.
 | 
						|
   */
 | 
						|
  private void pushInput(String name, ExternalIds ids, boolean report,
 | 
						|
                         boolean normalize)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    if (!externalEntities)
 | 
						|
      return;
 | 
						|
    String url = canonicalize(absolutize(input.systemId, ids.systemId));
 | 
						|
    // Check for recursion
 | 
						|
    for (Iterator i = inputStack.iterator(); i.hasNext(); )
 | 
						|
      {
 | 
						|
        Input ctx = (Input) i.next();
 | 
						|
        if (url.equals(ctx.systemId))
 | 
						|
          error("entities may not be self-recursive", url);
 | 
						|
        if (name != null && !"".equals(name) && name.equals(ctx.name))
 | 
						|
          error("entities may not be self-recursive", name);
 | 
						|
      }
 | 
						|
    if (name == null || "".equals(name))
 | 
						|
      report = false;
 | 
						|
    InputStream in = null;
 | 
						|
    if (resolver != null)
 | 
						|
      {
 | 
						|
        Object obj = resolver.resolveEntity(ids.publicId, url, getXMLBase(),
 | 
						|
                                            null);
 | 
						|
        if (obj instanceof InputStream)
 | 
						|
          in = (InputStream) obj;
 | 
						|
      }
 | 
						|
    if (in == null)
 | 
						|
      in = resolve(url);
 | 
						|
    if (in == null)
 | 
						|
      error("unable to resolve external entity",
 | 
						|
            (ids.systemId != null) ? ids.systemId : ids.publicId);
 | 
						|
    pushInput(new Input(in, null, ids.publicId, url, name, null, report,
 | 
						|
                        normalize));
 | 
						|
    input.init();
 | 
						|
    if (tryRead(TEST_XML_DECL))
 | 
						|
      readTextDecl();
 | 
						|
    input.finalizeEncoding();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Push the specified input source (general entity) onto the input stack.
 | 
						|
   */
 | 
						|
  private void pushInput(Input input)
 | 
						|
  {
 | 
						|
    if (input.report)
 | 
						|
      startEntityStack.addFirst(input.name);
 | 
						|
    inputStack.addLast(input);
 | 
						|
    if (this.input != null)
 | 
						|
      input.xml11 = this.input.xml11;
 | 
						|
    this.input = input;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns a canonicalized version of the specified URL.
 | 
						|
   * This is largely to work around a problem with the specification of
 | 
						|
   * file URLs.
 | 
						|
   */
 | 
						|
  static String canonicalize(String url)
 | 
						|
  {
 | 
						|
    if (url == null)
 | 
						|
      return null;
 | 
						|
    if (url.startsWith("file:") && !url.startsWith("file://"))
 | 
						|
      url = "file://" + url.substring(5);
 | 
						|
    return url;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * "Absolutize" a URL. This resolves a relative URL into an absolute one.
 | 
						|
   * @param base the current base URL
 | 
						|
   * @param href the (absolute or relative) URL to resolve
 | 
						|
   */
 | 
						|
  public static String absolutize(String base, String href)
 | 
						|
  {
 | 
						|
    if (href == null)
 | 
						|
      return null;
 | 
						|
    int ci = href.indexOf(':');
 | 
						|
    if (ci > 1 && isURLScheme(href.substring(0, ci)))
 | 
						|
      {
 | 
						|
        // href is absolute already
 | 
						|
        return href;
 | 
						|
      }
 | 
						|
    if (base == null)
 | 
						|
      base = "";
 | 
						|
    else
 | 
						|
      {
 | 
						|
        int i = base.lastIndexOf('/');
 | 
						|
        if (i != -1)
 | 
						|
          base = base.substring(0, i + 1);
 | 
						|
        else
 | 
						|
          base = "";
 | 
						|
      }
 | 
						|
    if ("".equals(base))
 | 
						|
      {
 | 
						|
        // assume file URL relative to current directory
 | 
						|
        base = System.getProperty("user.dir");
 | 
						|
        if (base.charAt(0) == '/')
 | 
						|
          base = base.substring(1);
 | 
						|
        base = "file:///" + base.replace(File.separatorChar, '/');
 | 
						|
        if (!base.endsWith("/"))
 | 
						|
          base += "/";
 | 
						|
      }
 | 
						|
    // We can't use java.net.URL here to do the parsing, as it searches for
 | 
						|
    // a protocol handler. A protocol handler may not be registered for the
 | 
						|
    // URL scheme here. Do it manually.
 | 
						|
    //
 | 
						|
    // Set aside scheme and host portion of base URL
 | 
						|
    String basePrefix = null;
 | 
						|
    ci = base.indexOf(':');
 | 
						|
    if (ci > 1 && isURLScheme(base.substring(0, ci)))
 | 
						|
      {
 | 
						|
          if (base.length() > (ci + 3)  &&
 | 
						|
              base.charAt(ci + 1) == '/' &&
 | 
						|
              base.charAt(ci + 2) == '/')
 | 
						|
            {
 | 
						|
              int si = base.indexOf('/', ci + 3);
 | 
						|
              if (si == -1)
 | 
						|
                base = null;
 | 
						|
              else
 | 
						|
                {
 | 
						|
                  basePrefix = base.substring(0, si);
 | 
						|
                  base = base.substring(si);
 | 
						|
                }
 | 
						|
            }
 | 
						|
          else
 | 
						|
            base = null;
 | 
						|
      }
 | 
						|
    if (base == null) // unknown or malformed base URL, use href
 | 
						|
      return href;
 | 
						|
    if (href.startsWith("/")) // absolute href pathname
 | 
						|
      return (basePrefix == null) ? href : basePrefix + href;
 | 
						|
    // relative href pathname
 | 
						|
    if (!base.endsWith("/"))
 | 
						|
      {
 | 
						|
        int lsi = base.lastIndexOf('/');
 | 
						|
        if (lsi == -1)
 | 
						|
          base = "/";
 | 
						|
        else
 | 
						|
          base = base.substring(0, lsi + 1);
 | 
						|
      }
 | 
						|
    while (href.startsWith("../") || href.startsWith("./"))
 | 
						|
      {
 | 
						|
        if (href.startsWith("../"))
 | 
						|
          {
 | 
						|
            // strip last path component from base
 | 
						|
            int lsi = base.lastIndexOf('/', base.length() - 2);
 | 
						|
            if (lsi > -1)
 | 
						|
              base = base.substring(0, lsi + 1);
 | 
						|
            href = href.substring(3); // strip ../ prefix
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            href = href.substring(2); // strip ./ prefix
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return (basePrefix == null) ? base + href : basePrefix + base + href;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates whether the specified characters match the scheme portion of
 | 
						|
   * a URL.
 | 
						|
   * @see RFC 1738 section 2.1
 | 
						|
   */
 | 
						|
  private static boolean isURLScheme(String text)
 | 
						|
  {
 | 
						|
    int len = text.length();
 | 
						|
    for (int i = 0; i < len; i++)
 | 
						|
      {
 | 
						|
        char c = text.charAt(i);
 | 
						|
        if (c == '+' || c == '.' || c == '-')
 | 
						|
          continue;
 | 
						|
        if (c < 65 || (c > 90 && c < 97) || c > 122)
 | 
						|
          return false;
 | 
						|
      }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns an input stream for the given URL.
 | 
						|
   */
 | 
						|
  static InputStream resolve(String url)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    try
 | 
						|
      {
 | 
						|
        return new URL(url).openStream();
 | 
						|
      }
 | 
						|
    catch (MalformedURLException e)
 | 
						|
      {
 | 
						|
        return null;
 | 
						|
      }
 | 
						|
    catch (IOException e)
 | 
						|
      {
 | 
						|
        IOException e2 = new IOException("error resolving " + url);
 | 
						|
        e2.initCause(e);
 | 
						|
        throw e2;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Pops the current input source (general entity) off the stack.
 | 
						|
   */
 | 
						|
  private void popInput()
 | 
						|
  {
 | 
						|
    Input old = (Input) inputStack.removeLast();
 | 
						|
    if (old.report)
 | 
						|
      endEntityStack.addFirst(old.name);
 | 
						|
    input = (Input) inputStack.getLast();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse an entity text declaration.
 | 
						|
   */
 | 
						|
  private void readTextDecl()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    final int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
 | 
						|
    requireWhitespace();
 | 
						|
    if (tryRead("version"))
 | 
						|
      {
 | 
						|
        readEq();
 | 
						|
        String v = readLiteral(flags, false);
 | 
						|
        if ("1.0".equals(v))
 | 
						|
          input.xml11 = false;
 | 
						|
        else if ("1.1".equals(v))
 | 
						|
          {
 | 
						|
            Input i1 = (Input) inputStack.getFirst();
 | 
						|
            if (!i1.xml11)
 | 
						|
              error("external entity specifies later version number");
 | 
						|
            input.xml11 = true;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          throw new XMLStreamException("illegal XML version: " + v);
 | 
						|
        requireWhitespace();
 | 
						|
      }
 | 
						|
    require("encoding");
 | 
						|
    readEq();
 | 
						|
    String enc = readLiteral(flags, false);
 | 
						|
    skipWhitespace();
 | 
						|
    require("?>");
 | 
						|
    input.setInputEncoding(enc);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse the XML declaration.
 | 
						|
   */
 | 
						|
  private void readXMLDecl()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    final int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
 | 
						|
 | 
						|
    requireWhitespace();
 | 
						|
    require("version");
 | 
						|
    readEq();
 | 
						|
    xmlVersion = readLiteral(flags, false);
 | 
						|
    if ("1.0".equals(xmlVersion))
 | 
						|
      input.xml11 = false;
 | 
						|
    else if ("1.1".equals(xmlVersion))
 | 
						|
      input.xml11 = true;
 | 
						|
    else
 | 
						|
      throw new XMLStreamException("illegal XML version: " + xmlVersion);
 | 
						|
 | 
						|
    boolean white = tryWhitespace();
 | 
						|
 | 
						|
    if (tryRead("encoding"))
 | 
						|
      {
 | 
						|
        if (!white)
 | 
						|
          error("whitespace required before 'encoding='");
 | 
						|
        readEq();
 | 
						|
        xmlEncoding = readLiteral(flags, false);
 | 
						|
        white = tryWhitespace();
 | 
						|
      }
 | 
						|
 | 
						|
    if (tryRead("standalone"))
 | 
						|
      {
 | 
						|
        if (!white)
 | 
						|
          error("whitespace required before 'standalone='");
 | 
						|
        readEq();
 | 
						|
        String standalone = readLiteral(flags, false);
 | 
						|
        if ("yes".equals(standalone))
 | 
						|
          xmlStandalone = Boolean.TRUE;
 | 
						|
        else if ("no".equals(standalone))
 | 
						|
          xmlStandalone = Boolean.FALSE;
 | 
						|
        else
 | 
						|
          error("standalone flag must be 'yes' or 'no'", standalone);
 | 
						|
      }
 | 
						|
 | 
						|
    skipWhitespace();
 | 
						|
    require("?>");
 | 
						|
    if (xmlEncoding != null)
 | 
						|
      input.setInputEncoding(xmlEncoding);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse the DOCTYPE declaration.
 | 
						|
   */
 | 
						|
  private void readDoctypeDecl()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    if (!supportDTD)
 | 
						|
      error("parser was configured not to support DTDs");
 | 
						|
    requireWhitespace();
 | 
						|
    String rootName = readNmtoken(true);
 | 
						|
    skipWhitespace();
 | 
						|
    ExternalIds ids = readExternalIds(false, true);
 | 
						|
    doctype =
 | 
						|
      this.new Doctype(rootName, ids.publicId, ids.systemId);
 | 
						|
 | 
						|
    // Parse internal subset first
 | 
						|
    skipWhitespace();
 | 
						|
    if (tryRead('['))
 | 
						|
      {
 | 
						|
        while (true)
 | 
						|
          {
 | 
						|
            expandPE = true;
 | 
						|
            skipWhitespace();
 | 
						|
            expandPE = false;
 | 
						|
            if (tryRead(']'))
 | 
						|
              break;
 | 
						|
            else
 | 
						|
              readMarkupdecl(false);
 | 
						|
          }
 | 
						|
      }
 | 
						|
    skipWhitespace();
 | 
						|
    require('>');
 | 
						|
 | 
						|
    // Parse external subset
 | 
						|
    if (ids.systemId != null && externalEntities)
 | 
						|
      {
 | 
						|
        pushInput("", ">", false, false);
 | 
						|
        pushInput("[dtd]", ids, true, true);
 | 
						|
        // loop until we get back to ">"
 | 
						|
        while (true)
 | 
						|
          {
 | 
						|
            expandPE = true;
 | 
						|
            skipWhitespace();
 | 
						|
            expandPE = false;
 | 
						|
            mark(1);
 | 
						|
            int c = readCh();
 | 
						|
            if (c == 0x3e) // '>'
 | 
						|
              break;
 | 
						|
            else if (c == -1)
 | 
						|
              popInput();
 | 
						|
            else
 | 
						|
              {
 | 
						|
                reset();
 | 
						|
                expandPE = true;
 | 
						|
                readMarkupdecl(true);
 | 
						|
                expandPE = true;
 | 
						|
              }
 | 
						|
          }
 | 
						|
        if (inputStack.size() != 2)
 | 
						|
          error("external subset has unmatched '>'");
 | 
						|
        popInput();
 | 
						|
      }
 | 
						|
    checkDoctype();
 | 
						|
    if (validating)
 | 
						|
      validateDoctype();
 | 
						|
 | 
						|
    // Make rootName available for reading
 | 
						|
    buf.setLength(0);
 | 
						|
    buf.append(rootName);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Checks the well-formedness of the DTD.
 | 
						|
   */
 | 
						|
  private void checkDoctype()
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    // TODO check entity recursion
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse the markupdecl production.
 | 
						|
   */
 | 
						|
  private void readMarkupdecl(boolean inExternalSubset)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    boolean saved = expandPE;
 | 
						|
    mark(1);
 | 
						|
    require('<');
 | 
						|
    reset();
 | 
						|
    expandPE = false;
 | 
						|
    if (tryRead(TEST_ELEMENT_DECL))
 | 
						|
      {
 | 
						|
        expandPE = saved;
 | 
						|
        readElementDecl();
 | 
						|
      }
 | 
						|
    else if (tryRead(TEST_ATTLIST_DECL))
 | 
						|
      {
 | 
						|
        expandPE = saved;
 | 
						|
        readAttlistDecl();
 | 
						|
      }
 | 
						|
    else if (tryRead(TEST_ENTITY_DECL))
 | 
						|
      {
 | 
						|
        expandPE = saved;
 | 
						|
        readEntityDecl(inExternalSubset);
 | 
						|
      }
 | 
						|
    else if (tryRead(TEST_NOTATION_DECL))
 | 
						|
      {
 | 
						|
        expandPE = saved;
 | 
						|
        readNotationDecl(inExternalSubset);
 | 
						|
      }
 | 
						|
    else if (tryRead(TEST_PI))
 | 
						|
      {
 | 
						|
        readPI(true);
 | 
						|
        expandPE = saved;
 | 
						|
      }
 | 
						|
    else if (tryRead(TEST_COMMENT))
 | 
						|
      {
 | 
						|
        readComment(true);
 | 
						|
        expandPE = saved;
 | 
						|
      }
 | 
						|
    else if (tryRead("<!["))
 | 
						|
      {
 | 
						|
        // conditional section
 | 
						|
        expandPE = saved;
 | 
						|
        if (inputStack.size() < 2)
 | 
						|
          error("conditional sections illegal in internal subset");
 | 
						|
        skipWhitespace();
 | 
						|
        if (tryRead("INCLUDE"))
 | 
						|
          {
 | 
						|
            skipWhitespace();
 | 
						|
            require('[');
 | 
						|
            skipWhitespace();
 | 
						|
            while (!tryRead("]]>"))
 | 
						|
              {
 | 
						|
                readMarkupdecl(inExternalSubset);
 | 
						|
                skipWhitespace();
 | 
						|
              }
 | 
						|
          }
 | 
						|
        else if (tryRead("IGNORE"))
 | 
						|
          {
 | 
						|
            skipWhitespace();
 | 
						|
            require('[');
 | 
						|
            expandPE = false;
 | 
						|
            for (int nesting = 1; nesting > 0; )
 | 
						|
              {
 | 
						|
                int c = readCh();
 | 
						|
                switch (c)
 | 
						|
                  {
 | 
						|
                  case 0x3c: // '<'
 | 
						|
                    if (tryRead("!["))
 | 
						|
                      nesting++;
 | 
						|
                    break;
 | 
						|
                  case 0x5d: // ']'
 | 
						|
                    if (tryRead("]>"))
 | 
						|
                      nesting--;
 | 
						|
                    break;
 | 
						|
                  case -1:
 | 
						|
                    throw new EOFException();
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            expandPE = saved;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          error("conditional section must begin with INCLUDE or IGNORE");
 | 
						|
      }
 | 
						|
    else
 | 
						|
      error("expected markup declaration");
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse the elementdecl production.
 | 
						|
   */
 | 
						|
  private void readElementDecl()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    requireWhitespace();
 | 
						|
    boolean saved = expandPE;
 | 
						|
    expandPE = (inputStack.size() > 1);
 | 
						|
    String name = readNmtoken(true);
 | 
						|
    expandPE = saved;
 | 
						|
    requireWhitespace();
 | 
						|
    readContentspec(name);
 | 
						|
    skipWhitespace();
 | 
						|
    require('>');
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse the contentspec production.
 | 
						|
   */
 | 
						|
  private void readContentspec(String elementName)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    if (tryRead("EMPTY"))
 | 
						|
      doctype.addElementDecl(elementName, "EMPTY", new EmptyContentModel());
 | 
						|
    else if (tryRead("ANY"))
 | 
						|
      doctype.addElementDecl(elementName, "ANY", new AnyContentModel());
 | 
						|
    else
 | 
						|
      {
 | 
						|
        ContentModel model;
 | 
						|
        CPStringBuilder acc = new CPStringBuilder();
 | 
						|
        require('(');
 | 
						|
        acc.append('(');
 | 
						|
        skipWhitespace();
 | 
						|
        if (tryRead("#PCDATA"))
 | 
						|
          {
 | 
						|
            // mixed content
 | 
						|
            acc.append("#PCDATA");
 | 
						|
            MixedContentModel mm = new MixedContentModel();
 | 
						|
            model = mm;
 | 
						|
            skipWhitespace();
 | 
						|
            if (tryRead(')'))
 | 
						|
              {
 | 
						|
                acc.append(")");
 | 
						|
                if (tryRead('*'))
 | 
						|
                  {
 | 
						|
                    mm.min = 0;
 | 
						|
                    mm.max = -1;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                while (!tryRead(")"))
 | 
						|
                  {
 | 
						|
                    require('|');
 | 
						|
                    acc.append('|');
 | 
						|
                    skipWhitespace();
 | 
						|
                    String name = readNmtoken(true);
 | 
						|
                    acc.append(name);
 | 
						|
                    mm.addName(name);
 | 
						|
                    skipWhitespace();
 | 
						|
                  }
 | 
						|
                require('*');
 | 
						|
                acc.append(")*");
 | 
						|
                mm.min = 0;
 | 
						|
                mm.max = -1;
 | 
						|
              }
 | 
						|
          }
 | 
						|
        else
 | 
						|
          model = readElements(acc);
 | 
						|
        doctype.addElementDecl(elementName, acc.toString(), model);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parses an element content model.
 | 
						|
   */
 | 
						|
  private ElementContentModel readElements(CPStringBuilder acc)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    int separator;
 | 
						|
    ElementContentModel model = new ElementContentModel();
 | 
						|
 | 
						|
    // Parse first content particle
 | 
						|
    skipWhitespace();
 | 
						|
    model.addContentParticle(readContentParticle(acc));
 | 
						|
    // End or separator
 | 
						|
    skipWhitespace();
 | 
						|
    int c = readCh();
 | 
						|
    switch (c)
 | 
						|
      {
 | 
						|
      case 0x29: // ')'
 | 
						|
        acc.append(')');
 | 
						|
        mark(1);
 | 
						|
        c = readCh();
 | 
						|
        switch (c)
 | 
						|
          {
 | 
						|
          case 0x3f: // '?'
 | 
						|
            acc.append('?');
 | 
						|
            model.min = 0;
 | 
						|
            model.max = 1;
 | 
						|
            break;
 | 
						|
          case 0x2a: // '*'
 | 
						|
            acc.append('*');
 | 
						|
            model.min = 0;
 | 
						|
            model.max = -1;
 | 
						|
            break;
 | 
						|
          case 0x2b: // '+'
 | 
						|
            acc.append('+');
 | 
						|
            model.min = 1;
 | 
						|
            model.max = -1;
 | 
						|
            break;
 | 
						|
          default:
 | 
						|
            reset();
 | 
						|
          }
 | 
						|
        return model; // done
 | 
						|
      case 0x7c: // '|'
 | 
						|
        model.or = true;
 | 
						|
        // fall through
 | 
						|
      case 0x2c: // ','
 | 
						|
        separator = c;
 | 
						|
        acc.append(Character.toChars(c));
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
        error("bad separator in content model",
 | 
						|
              "U+" + Integer.toHexString(c));
 | 
						|
        return model;
 | 
						|
      }
 | 
						|
    // Parse subsequent content particles
 | 
						|
    while (true)
 | 
						|
      {
 | 
						|
        skipWhitespace();
 | 
						|
        model.addContentParticle(readContentParticle(acc));
 | 
						|
        skipWhitespace();
 | 
						|
        c = readCh();
 | 
						|
        if (c == 0x29) // ')'
 | 
						|
          {
 | 
						|
            acc.append(')');
 | 
						|
            break;
 | 
						|
          }
 | 
						|
        else if (c != separator)
 | 
						|
          {
 | 
						|
            error("bad separator in content model",
 | 
						|
                  "U+" + Integer.toHexString(c));
 | 
						|
            return model;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          acc.append(c);
 | 
						|
      }
 | 
						|
    // Check for occurrence indicator
 | 
						|
    mark(1);
 | 
						|
    c = readCh();
 | 
						|
    switch (c)
 | 
						|
      {
 | 
						|
      case 0x3f: // '?'
 | 
						|
        acc.append('?');
 | 
						|
        model.min = 0;
 | 
						|
        model.max = 1;
 | 
						|
        break;
 | 
						|
      case 0x2a: // '*'
 | 
						|
        acc.append('*');
 | 
						|
        model.min = 0;
 | 
						|
        model.max = -1;
 | 
						|
        break;
 | 
						|
      case 0x2b: // '+'
 | 
						|
        acc.append('+');
 | 
						|
        model.min = 1;
 | 
						|
        model.max = -1;
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
        reset();
 | 
						|
      }
 | 
						|
    return model;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse a cp production.
 | 
						|
   */
 | 
						|
  private ContentParticle readContentParticle(CPStringBuilder acc)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    ContentParticle cp = new ContentParticle();
 | 
						|
    if (tryRead('('))
 | 
						|
      {
 | 
						|
        acc.append('(');
 | 
						|
        cp.content = readElements(acc);
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        String name = readNmtoken(true);
 | 
						|
        acc.append(name);
 | 
						|
        cp.content = name;
 | 
						|
        mark(1);
 | 
						|
        int c = readCh();
 | 
						|
        switch (c)
 | 
						|
          {
 | 
						|
          case 0x3f: // '?'
 | 
						|
            acc.append('?');
 | 
						|
            cp.min = 0;
 | 
						|
            cp.max = 1;
 | 
						|
            break;
 | 
						|
          case 0x2a: // '*'
 | 
						|
            acc.append('*');
 | 
						|
            cp.min = 0;
 | 
						|
            cp.max = -1;
 | 
						|
            break;
 | 
						|
          case 0x2b: // '+'
 | 
						|
            acc.append('+');
 | 
						|
            cp.min = 1;
 | 
						|
            cp.max = -1;
 | 
						|
            break;
 | 
						|
          default:
 | 
						|
            reset();
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return cp;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse an attribute-list definition.
 | 
						|
   */
 | 
						|
  private void readAttlistDecl()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    requireWhitespace();
 | 
						|
    boolean saved = expandPE;
 | 
						|
    expandPE = (inputStack.size() > 1);
 | 
						|
    String elementName = readNmtoken(true);
 | 
						|
    expandPE = saved;
 | 
						|
    boolean white = tryWhitespace();
 | 
						|
    while (!tryRead('>'))
 | 
						|
      {
 | 
						|
        if (!white)
 | 
						|
          error("whitespace required before attribute definition");
 | 
						|
        readAttDef(elementName);
 | 
						|
        white = tryWhitespace();
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse a single attribute definition.
 | 
						|
   */
 | 
						|
  private void readAttDef(String elementName)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    String name = readNmtoken(true);
 | 
						|
    requireWhitespace();
 | 
						|
    CPStringBuilder acc = new CPStringBuilder();
 | 
						|
    HashSet values = new HashSet();
 | 
						|
    String type = readAttType(acc, values);
 | 
						|
    if (validating)
 | 
						|
      {
 | 
						|
        if ("ID".equals(type))
 | 
						|
          {
 | 
						|
            // VC: One ID per Element Type
 | 
						|
            for (Iterator i = doctype.attlistIterator(elementName);
 | 
						|
                 i.hasNext(); )
 | 
						|
              {
 | 
						|
                Map.Entry entry = (Map.Entry) i.next();
 | 
						|
                AttributeDecl decl = (AttributeDecl) entry.getValue();
 | 
						|
                if ("ID".equals(decl.type))
 | 
						|
                  error("element types must not have more than one ID " +
 | 
						|
                        "attribute");
 | 
						|
              }
 | 
						|
          }
 | 
						|
        else if ("NOTATION".equals(type))
 | 
						|
          {
 | 
						|
            // VC: One Notation Per Element Type
 | 
						|
            for (Iterator i = doctype.attlistIterator(elementName);
 | 
						|
                 i.hasNext(); )
 | 
						|
              {
 | 
						|
                Map.Entry entry = (Map.Entry) i.next();
 | 
						|
                AttributeDecl decl = (AttributeDecl) entry.getValue();
 | 
						|
                if ("NOTATION".equals(decl.type))
 | 
						|
                  error("element types must not have more than one NOTATION " +
 | 
						|
                        "attribute");
 | 
						|
              }
 | 
						|
            // VC: No Notation on Empty Element
 | 
						|
            ContentModel model = doctype.getElementModel(elementName);
 | 
						|
            if (model != null && model.type == ContentModel.EMPTY)
 | 
						|
              error("attributes of type NOTATION must not be declared on an " +
 | 
						|
                    "element declared EMPTY");
 | 
						|
          }
 | 
						|
      }
 | 
						|
    String enumer = null;
 | 
						|
    if ("ENUMERATION".equals(type) || "NOTATION".equals(type))
 | 
						|
      enumer = acc.toString();
 | 
						|
    else
 | 
						|
      values = null;
 | 
						|
    requireWhitespace();
 | 
						|
    readDefault(elementName, name, type, enumer, values);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse an attribute type.
 | 
						|
   */
 | 
						|
  private String readAttType(CPStringBuilder acc, HashSet values)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    if (tryRead('('))
 | 
						|
      {
 | 
						|
        readEnumeration(false, acc, values);
 | 
						|
        return "ENUMERATION";
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        String typeString = readNmtoken(true);
 | 
						|
        if ("NOTATION".equals(typeString))
 | 
						|
          {
 | 
						|
            readNotationType(acc, values);
 | 
						|
            return typeString;
 | 
						|
          }
 | 
						|
        else if ("CDATA".equals(typeString) ||
 | 
						|
                 "ID".equals(typeString) ||
 | 
						|
                 "IDREF".equals(typeString) ||
 | 
						|
                 "IDREFS".equals(typeString) ||
 | 
						|
                 "ENTITY".equals(typeString) ||
 | 
						|
                 "ENTITIES".equals(typeString) ||
 | 
						|
                 "NMTOKEN".equals(typeString) ||
 | 
						|
                 "NMTOKENS".equals(typeString))
 | 
						|
          return typeString;
 | 
						|
        else
 | 
						|
          {
 | 
						|
            error("illegal attribute type", typeString);
 | 
						|
            return null;
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse an enumeration.
 | 
						|
   */
 | 
						|
  private void readEnumeration(boolean isNames, CPStringBuilder acc,
 | 
						|
                               HashSet values)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    acc.append('(');
 | 
						|
    // first token
 | 
						|
    skipWhitespace();
 | 
						|
    String token = readNmtoken(isNames);
 | 
						|
    acc.append(token);
 | 
						|
    values.add(token);
 | 
						|
    // subsequent tokens
 | 
						|
    skipWhitespace();
 | 
						|
    while (!tryRead(')'))
 | 
						|
      {
 | 
						|
        require('|');
 | 
						|
        acc.append('|');
 | 
						|
        skipWhitespace();
 | 
						|
        token = readNmtoken(isNames);
 | 
						|
        // VC: No Duplicate Tokens
 | 
						|
        if (validating && values.contains(token))
 | 
						|
          error("duplicate token", token);
 | 
						|
        acc.append(token);
 | 
						|
        values.add(token);
 | 
						|
        skipWhitespace();
 | 
						|
      }
 | 
						|
    acc.append(')');
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse a notation type for an attribute.
 | 
						|
   */
 | 
						|
  private void readNotationType(CPStringBuilder acc, HashSet values)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    requireWhitespace();
 | 
						|
    require('(');
 | 
						|
    readEnumeration(true, acc, values);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse the default value for an attribute.
 | 
						|
   */
 | 
						|
  private void readDefault(String elementName, String name,
 | 
						|
                           String type, String enumeration, HashSet values)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    int valueType = ATTRIBUTE_DEFAULT_SPECIFIED;
 | 
						|
    int flags = LIT_ATTRIBUTE;
 | 
						|
    String value = null, defaultType = null;
 | 
						|
    boolean saved = expandPE;
 | 
						|
 | 
						|
    if (!"CDATA".equals(type))
 | 
						|
      flags |= LIT_NORMALIZE;
 | 
						|
 | 
						|
    expandPE = false;
 | 
						|
    if (tryRead('#'))
 | 
						|
      {
 | 
						|
        if (tryRead("FIXED"))
 | 
						|
          {
 | 
						|
            defaultType = "#FIXED";
 | 
						|
            valueType = ATTRIBUTE_DEFAULT_FIXED;
 | 
						|
            requireWhitespace();
 | 
						|
            value = readLiteral(flags, false);
 | 
						|
          }
 | 
						|
        else if (tryRead("REQUIRED"))
 | 
						|
          {
 | 
						|
            defaultType = "#REQUIRED";
 | 
						|
            valueType = ATTRIBUTE_DEFAULT_REQUIRED;
 | 
						|
          }
 | 
						|
        else if (tryRead("IMPLIED"))
 | 
						|
          {
 | 
						|
            defaultType = "#IMPLIED";
 | 
						|
            valueType = ATTRIBUTE_DEFAULT_IMPLIED;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          error("illegal keyword for attribute default value");
 | 
						|
      }
 | 
						|
    else
 | 
						|
      value = readLiteral(flags, false);
 | 
						|
    expandPE = saved;
 | 
						|
    if (validating)
 | 
						|
      {
 | 
						|
        if ("ID".equals(type))
 | 
						|
          {
 | 
						|
            // VC: Attribute Default Value Syntactically Correct
 | 
						|
            if (value != null && !isNmtoken(value, true))
 | 
						|
              error("default value must match Name production", value);
 | 
						|
            // VC: ID Attribute Default
 | 
						|
            if (valueType != ATTRIBUTE_DEFAULT_REQUIRED &&
 | 
						|
                valueType != ATTRIBUTE_DEFAULT_IMPLIED)
 | 
						|
              error("ID attributes must have a declared default of " +
 | 
						|
                    "#IMPLIED or #REQUIRED");
 | 
						|
          }
 | 
						|
        else if (value != null)
 | 
						|
          {
 | 
						|
            // VC: Attribute Default Value Syntactically Correct
 | 
						|
            if ("IDREF".equals(type) || "ENTITY".equals(type))
 | 
						|
              {
 | 
						|
                if (!isNmtoken(value, true))
 | 
						|
                  error("default value must match Name production", value);
 | 
						|
              }
 | 
						|
            else if ("IDREFS".equals(type) || "ENTITIES".equals(type))
 | 
						|
              {
 | 
						|
                StringTokenizer st = new StringTokenizer(value);
 | 
						|
                while (st.hasMoreTokens())
 | 
						|
                  {
 | 
						|
                    String token = st.nextToken();
 | 
						|
                    if (!isNmtoken(token, true))
 | 
						|
                      error("default value must match Name production", token);
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            else if ("NMTOKEN".equals(type) || "ENUMERATION".equals(type))
 | 
						|
              {
 | 
						|
                if (!isNmtoken(value, false))
 | 
						|
                  error("default value must match Nmtoken production", value);
 | 
						|
              }
 | 
						|
            else if ("NMTOKENS".equals(type))
 | 
						|
              {
 | 
						|
                StringTokenizer st = new StringTokenizer(value);
 | 
						|
                while (st.hasMoreTokens())
 | 
						|
                  {
 | 
						|
                    String token = st.nextToken();
 | 
						|
                    if (!isNmtoken(token, false))
 | 
						|
                      error("default value must match Nmtoken production",
 | 
						|
                            token);
 | 
						|
                  }
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
    // Register attribute def
 | 
						|
    AttributeDecl attribute =
 | 
						|
      new AttributeDecl(type, value, valueType, enumeration, values,
 | 
						|
                        inputStack.size() != 1);
 | 
						|
    doctype.addAttributeDecl(elementName, name, attribute);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse the EntityDecl production.
 | 
						|
   */
 | 
						|
  private void readEntityDecl(boolean inExternalSubset)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    int flags = 0;
 | 
						|
    // Check if parameter entity
 | 
						|
    boolean peFlag = false;
 | 
						|
    expandPE = false;
 | 
						|
    requireWhitespace();
 | 
						|
    if (tryRead('%'))
 | 
						|
      {
 | 
						|
        peFlag = true;
 | 
						|
        requireWhitespace();
 | 
						|
      }
 | 
						|
    expandPE = true;
 | 
						|
    // Read entity name
 | 
						|
    String name = readNmtoken(true);
 | 
						|
    if (name.indexOf(':') != -1)
 | 
						|
      error("illegal character ':' in entity name", name);
 | 
						|
    if (peFlag)
 | 
						|
      name = "%" + name;
 | 
						|
    requireWhitespace();
 | 
						|
    mark(1);
 | 
						|
    int c = readCh();
 | 
						|
    reset();
 | 
						|
    if (c == 0x22 || c == 0x27) // " | '
 | 
						|
      {
 | 
						|
        // Internal entity replacement text
 | 
						|
        String value = readLiteral(flags | LIT_DISABLE_EREF, true);
 | 
						|
        int ai = value.indexOf('&');
 | 
						|
        while (ai != -1)
 | 
						|
          {
 | 
						|
            int sci = value.indexOf(';', ai);
 | 
						|
            if (sci == -1)
 | 
						|
              error("malformed reference in entity value", value);
 | 
						|
            String ref = value.substring(ai + 1, sci);
 | 
						|
            int[] cp = UnicodeReader.toCodePointArray(ref);
 | 
						|
            if (cp.length == 0)
 | 
						|
              error("malformed reference in entity value", value);
 | 
						|
            if (cp[0] == 0x23) // #
 | 
						|
              {
 | 
						|
                if (cp.length == 1)
 | 
						|
                  error("malformed reference in entity value", value);
 | 
						|
                if (cp[1] == 0x78) // 'x'
 | 
						|
                  {
 | 
						|
                    if (cp.length == 2)
 | 
						|
                      error("malformed reference in entity value", value);
 | 
						|
                    for (int i = 2; i < cp.length; i++)
 | 
						|
                      {
 | 
						|
                        int x = cp[i];
 | 
						|
                        if (x < 0x30 ||
 | 
						|
                            (x > 0x39 && x < 0x41) ||
 | 
						|
                            (x > 0x46 && x < 0x61) ||
 | 
						|
                            x > 0x66)
 | 
						|
                          error("malformed character reference in entity value",
 | 
						|
                                value);
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  {
 | 
						|
                    for (int i = 1; i < cp.length; i++)
 | 
						|
                      {
 | 
						|
                        int x = cp[i];
 | 
						|
                        if (x < 0x30 || x > 0x39)
 | 
						|
                          error("malformed character reference in entity value",
 | 
						|
                                value);
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                if (!isNameStartCharacter(cp[0], input.xml11))
 | 
						|
                  error("malformed reference in entity value", value);
 | 
						|
                for (int i = 1; i < cp.length; i++)
 | 
						|
                  {
 | 
						|
                    if (!isNameCharacter(cp[i], input.xml11))
 | 
						|
                      error("malformed reference in entity value", value);
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            ai = value.indexOf('&', sci);
 | 
						|
          }
 | 
						|
        doctype.addEntityDecl(name, value, inExternalSubset);
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        ExternalIds ids = readExternalIds(false, false);
 | 
						|
        // Check for NDATA
 | 
						|
        boolean white = tryWhitespace();
 | 
						|
        if (!peFlag && tryRead("NDATA"))
 | 
						|
          {
 | 
						|
            if (!white)
 | 
						|
              error("whitespace required before NDATA");
 | 
						|
            requireWhitespace();
 | 
						|
            ids.notationName = readNmtoken(true);
 | 
						|
          }
 | 
						|
        doctype.addEntityDecl(name, ids, inExternalSubset);
 | 
						|
      }
 | 
						|
    // finish
 | 
						|
    skipWhitespace();
 | 
						|
    require('>');
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse the NotationDecl production.
 | 
						|
   */
 | 
						|
  private void readNotationDecl(boolean inExternalSubset)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    requireWhitespace();
 | 
						|
    String notationName = readNmtoken(true);
 | 
						|
    if (notationName.indexOf(':') != -1)
 | 
						|
      error("illegal character ':' in notation name", notationName);
 | 
						|
    if (validating)
 | 
						|
      {
 | 
						|
        // VC: Unique Notation Name
 | 
						|
        ExternalIds notation = doctype.getNotation(notationName);
 | 
						|
        if (notation != null)
 | 
						|
          error("duplicate notation name", notationName);
 | 
						|
      }
 | 
						|
    requireWhitespace();
 | 
						|
    ExternalIds ids = readExternalIds(true, false);
 | 
						|
    ids.notationName = notationName;
 | 
						|
    doctype.addNotationDecl(notationName, ids, inExternalSubset);
 | 
						|
    skipWhitespace();
 | 
						|
    require('>');
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns a tuple {publicId, systemId}.
 | 
						|
   */
 | 
						|
  private ExternalIds readExternalIds(boolean inNotation, boolean isSubset)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    int c;
 | 
						|
    int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
 | 
						|
    ExternalIds ids = new ExternalIds();
 | 
						|
 | 
						|
    if (tryRead("PUBLIC"))
 | 
						|
      {
 | 
						|
        requireWhitespace();
 | 
						|
        ids.publicId = readLiteral(LIT_NORMALIZE | LIT_PUBID | flags, false);
 | 
						|
        if (inNotation)
 | 
						|
          {
 | 
						|
            skipWhitespace();
 | 
						|
            mark(1);
 | 
						|
            c = readCh();
 | 
						|
            reset();
 | 
						|
            if (c == 0x22 || c == 0x27) // " | '
 | 
						|
              {
 | 
						|
                String href = readLiteral(flags, false);
 | 
						|
                ids.systemId = absolutize(input.systemId, href);
 | 
						|
              }
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            requireWhitespace();
 | 
						|
            String href = readLiteral(flags, false);
 | 
						|
            ids.systemId = absolutize(input.systemId, href);
 | 
						|
          }
 | 
						|
        // Check valid URI characters
 | 
						|
        for (int i = 0; i < ids.publicId.length(); i++)
 | 
						|
          {
 | 
						|
            char d = ids.publicId.charAt(i);
 | 
						|
            if (d >= 'a' && d <= 'z')
 | 
						|
              continue;
 | 
						|
            if (d >= 'A' && d <= 'Z')
 | 
						|
              continue;
 | 
						|
            if (" \r\n0123456789-' ()+,./:=?;!*#@$_%".indexOf(d) != -1)
 | 
						|
              continue;
 | 
						|
            error("illegal PUBLIC id character",
 | 
						|
                  "U+" + Integer.toHexString(d));
 | 
						|
          }
 | 
						|
      }
 | 
						|
    else if (tryRead("SYSTEM"))
 | 
						|
      {
 | 
						|
        requireWhitespace();
 | 
						|
        String href = readLiteral(flags, false);
 | 
						|
        ids.systemId = absolutize(input.systemId, href);
 | 
						|
      }
 | 
						|
    else if (!isSubset)
 | 
						|
      {
 | 
						|
        error("missing SYSTEM or PUBLIC keyword");
 | 
						|
      }
 | 
						|
    if (ids.systemId != null && !inNotation)
 | 
						|
      {
 | 
						|
        if (ids.systemId.indexOf('#') != -1)
 | 
						|
          error("SYSTEM id has a URI fragment", ids.systemId);
 | 
						|
      }
 | 
						|
    return ids;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse the start of an element.
 | 
						|
   * @return the state of the parser afterwards (EMPTY_ELEMENT or CONTENT)
 | 
						|
   */
 | 
						|
  private int readStartElement()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    // Read element name
 | 
						|
    String elementName = readNmtoken(true);
 | 
						|
    attrs.clear();
 | 
						|
    // Push namespace context
 | 
						|
    if (namespaceAware)
 | 
						|
      {
 | 
						|
        if (elementName.charAt(0) == ':' ||
 | 
						|
            elementName.charAt(elementName.length() - 1) == ':')
 | 
						|
          error("not a QName", elementName);
 | 
						|
        namespaces.addFirst(new LinkedHashMap());
 | 
						|
      }
 | 
						|
    // Read element content
 | 
						|
    boolean white = tryWhitespace();
 | 
						|
    mark(1);
 | 
						|
    int c = readCh();
 | 
						|
    while (c != 0x2f && c != 0x3e) // '/' | '>'
 | 
						|
      {
 | 
						|
        // Read attribute
 | 
						|
        reset();
 | 
						|
        if (!white)
 | 
						|
          error("need whitespace between attributes");
 | 
						|
        readAttribute(elementName);
 | 
						|
        white = tryWhitespace();
 | 
						|
        mark(1);
 | 
						|
        c = readCh();
 | 
						|
      }
 | 
						|
    // supply defaulted attributes
 | 
						|
    if (doctype != null)
 | 
						|
      {
 | 
						|
        for (Iterator i = doctype.attlistIterator(elementName); i.hasNext(); )
 | 
						|
          {
 | 
						|
            Map.Entry entry = (Map.Entry) i.next();
 | 
						|
            String attName = (String) entry.getKey();
 | 
						|
            AttributeDecl decl = (AttributeDecl) entry.getValue();
 | 
						|
            if (validating)
 | 
						|
              {
 | 
						|
                switch (decl.valueType)
 | 
						|
                  {
 | 
						|
                  case ATTRIBUTE_DEFAULT_REQUIRED:
 | 
						|
                    // VC: Required Attribute
 | 
						|
                    if (decl.value == null && !attributeSpecified(attName))
 | 
						|
                      error("value for " + attName + " attribute is required");
 | 
						|
                    break;
 | 
						|
                  case ATTRIBUTE_DEFAULT_FIXED:
 | 
						|
                    // VC: Fixed Attribute Default
 | 
						|
                    for (Iterator j = attrs.iterator(); j.hasNext(); )
 | 
						|
                      {
 | 
						|
                        Attribute a = (Attribute) j.next();
 | 
						|
                        if (attName.equals(a.name) &&
 | 
						|
                            !decl.value.equals(a.value))
 | 
						|
                          error("value for " + attName + " attribute must be " +
 | 
						|
                                decl.value);
 | 
						|
                      }
 | 
						|
                    break;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            if (namespaceAware && attName.equals("xmlns"))
 | 
						|
              {
 | 
						|
                LinkedHashMap ctx =
 | 
						|
                  (LinkedHashMap) namespaces.getFirst();
 | 
						|
                if (ctx.containsKey(XMLConstants.DEFAULT_NS_PREFIX))
 | 
						|
                  continue; // namespace was specified
 | 
						|
              }
 | 
						|
            else if (namespaceAware && attName.startsWith("xmlns:"))
 | 
						|
              {
 | 
						|
                LinkedHashMap ctx =
 | 
						|
                  (LinkedHashMap) namespaces.getFirst();
 | 
						|
                if (ctx.containsKey(attName.substring(6)))
 | 
						|
                  continue; // namespace was specified
 | 
						|
              }
 | 
						|
            else if (attributeSpecified(attName))
 | 
						|
              continue;
 | 
						|
            if (decl.value == null)
 | 
						|
              continue;
 | 
						|
            // VC: Standalone Document Declaration
 | 
						|
            if (validating && decl.external && xmlStandalone == Boolean.TRUE)
 | 
						|
              error("standalone must be 'no' if attributes inherit values " +
 | 
						|
                    "from externally declared markup declarations");
 | 
						|
            Attribute attr =
 | 
						|
              new Attribute(attName, decl.type, false, decl.value);
 | 
						|
            if (namespaceAware)
 | 
						|
              {
 | 
						|
                if (!addNamespace(attr))
 | 
						|
                  attrs.add(attr);
 | 
						|
              }
 | 
						|
            else
 | 
						|
              attrs.add(attr);
 | 
						|
          }
 | 
						|
      }
 | 
						|
    if (baseAware)
 | 
						|
      {
 | 
						|
        String uri = getAttributeValue(XMLConstants.XML_NS_URI, "base");
 | 
						|
        String base = getXMLBase();
 | 
						|
        bases.addFirst(absolutize(base, uri));
 | 
						|
      }
 | 
						|
    if (namespaceAware)
 | 
						|
      {
 | 
						|
        // check prefix bindings
 | 
						|
        int ci = elementName.indexOf(':');
 | 
						|
        if (ci != -1)
 | 
						|
          {
 | 
						|
            String prefix = elementName.substring(0, ci);
 | 
						|
            String uri = getNamespaceURI(prefix);
 | 
						|
            if (uri == null)
 | 
						|
              error("unbound element prefix", prefix);
 | 
						|
            else if (input.xml11 && "".equals(uri))
 | 
						|
              error("XML 1.1 unbound element prefix", prefix);
 | 
						|
          }
 | 
						|
        for (Iterator i = attrs.iterator(); i.hasNext(); )
 | 
						|
          {
 | 
						|
            Attribute attr = (Attribute) i.next();
 | 
						|
            if (attr.prefix != null &&
 | 
						|
                !XMLConstants.XMLNS_ATTRIBUTE.equals(attr.prefix))
 | 
						|
              {
 | 
						|
                String uri = getNamespaceURI(attr.prefix);
 | 
						|
                if (uri == null)
 | 
						|
                  error("unbound attribute prefix", attr.prefix);
 | 
						|
                else if (input.xml11 && "".equals(uri))
 | 
						|
                  error("XML 1.1 unbound attribute prefix", attr.prefix);
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
    if (validating && doctype != null)
 | 
						|
      {
 | 
						|
        validateStartElement(elementName);
 | 
						|
        currentContentModel = doctype.getElementModel(elementName);
 | 
						|
        if (currentContentModel == null)
 | 
						|
          error("no element declaration", elementName);
 | 
						|
        validationStack.add(new LinkedList());
 | 
						|
      }
 | 
						|
    // make element name available for read
 | 
						|
    buf.setLength(0);
 | 
						|
    buf.append(elementName);
 | 
						|
    // push element onto stack
 | 
						|
    stack.addLast(elementName);
 | 
						|
    switch (c)
 | 
						|
      {
 | 
						|
      case 0x3e: // '>'
 | 
						|
        return CONTENT;
 | 
						|
      case 0x2f: // '/'
 | 
						|
        require('>');
 | 
						|
        return EMPTY_ELEMENT;
 | 
						|
      }
 | 
						|
    return -1; // to satisfy compiler
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates whether the specified attribute name was specified for the
 | 
						|
   * current element.
 | 
						|
   */
 | 
						|
  private boolean attributeSpecified(String attName)
 | 
						|
  {
 | 
						|
    for (Iterator j = attrs.iterator(); j.hasNext(); )
 | 
						|
      {
 | 
						|
        Attribute a = (Attribute) j.next();
 | 
						|
        if (attName.equals(a.name))
 | 
						|
          return true;
 | 
						|
      }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse an attribute.
 | 
						|
   */
 | 
						|
  private void readAttribute(String elementName)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    // Read attribute name
 | 
						|
    String attributeName = readNmtoken(true);
 | 
						|
    String type = getAttributeType(elementName, attributeName);
 | 
						|
    readEq();
 | 
						|
    // Read literal
 | 
						|
    final int flags = LIT_ATTRIBUTE |  LIT_ENTITY_REF;
 | 
						|
    String value = (type == null || "CDATA".equals(type)) ?
 | 
						|
      readLiteral(flags, false) : readLiteral(flags | LIT_NORMALIZE, false);
 | 
						|
    // add attribute event
 | 
						|
    Attribute attr = this.new Attribute(attributeName, type, true, value);
 | 
						|
    if (namespaceAware)
 | 
						|
      {
 | 
						|
        if (attributeName.charAt(0) == ':' ||
 | 
						|
            attributeName.charAt(attributeName.length() - 1) == ':')
 | 
						|
          error("not a QName", attributeName);
 | 
						|
        else if (attributeName.equals("xmlns"))
 | 
						|
          {
 | 
						|
            LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
 | 
						|
            if (ctx.containsKey(XMLConstants.DEFAULT_NS_PREFIX))
 | 
						|
              error("duplicate default namespace");
 | 
						|
          }
 | 
						|
        else if (attributeName.startsWith("xmlns:"))
 | 
						|
          {
 | 
						|
            LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
 | 
						|
            if (ctx.containsKey(attributeName.substring(6)))
 | 
						|
              error("duplicate namespace", attributeName.substring(6));
 | 
						|
          }
 | 
						|
        else if (attrs.contains(attr))
 | 
						|
          error("duplicate attribute", attributeName);
 | 
						|
      }
 | 
						|
    else if (attrs.contains(attr))
 | 
						|
      error("duplicate attribute", attributeName);
 | 
						|
    if (validating && doctype != null)
 | 
						|
      {
 | 
						|
        // VC: Attribute Value Type
 | 
						|
        AttributeDecl decl =
 | 
						|
          doctype.getAttributeDecl(elementName, attributeName);
 | 
						|
        if (decl == null)
 | 
						|
          error("attribute must be declared", attributeName);
 | 
						|
        if ("ENUMERATION".equals(decl.type))
 | 
						|
          {
 | 
						|
            // VC: Enumeration
 | 
						|
            if (!decl.values.contains(value))
 | 
						|
              error("value does not match enumeration " + decl.enumeration,
 | 
						|
                    value);
 | 
						|
          }
 | 
						|
        else if ("ID".equals(decl.type))
 | 
						|
          {
 | 
						|
            // VC: ID
 | 
						|
            if (!isNmtoken(value, true))
 | 
						|
              error("ID values must match the Name production");
 | 
						|
            if (ids.contains(value))
 | 
						|
              error("Duplicate ID", value);
 | 
						|
            ids.add(value);
 | 
						|
          }
 | 
						|
        else if ("IDREF".equals(decl.type) || "IDREFS".equals(decl.type))
 | 
						|
          {
 | 
						|
            StringTokenizer st = new StringTokenizer(value);
 | 
						|
            while (st.hasMoreTokens())
 | 
						|
              {
 | 
						|
                String token = st.nextToken();
 | 
						|
                // VC: IDREF
 | 
						|
                if (!isNmtoken(token, true))
 | 
						|
                  error("IDREF values must match the Name production");
 | 
						|
                idrefs.add(token);
 | 
						|
              }
 | 
						|
          }
 | 
						|
        else if ("NMTOKEN".equals(decl.type) || "NMTOKENS".equals(decl.type))
 | 
						|
          {
 | 
						|
            StringTokenizer st = new StringTokenizer(value);
 | 
						|
            while (st.hasMoreTokens())
 | 
						|
              {
 | 
						|
                String token = st.nextToken();
 | 
						|
                // VC: Name Token
 | 
						|
                if (!isNmtoken(token, false))
 | 
						|
                  error("NMTOKEN values must match the Nmtoken production");
 | 
						|
              }
 | 
						|
          }
 | 
						|
        else if ("ENTITY".equals(decl.type))
 | 
						|
          {
 | 
						|
            // VC: Entity Name
 | 
						|
            if (!isNmtoken(value, true))
 | 
						|
              error("ENTITY values must match the Name production");
 | 
						|
            Object entity = doctype.getEntity(value);
 | 
						|
            if (entity == null || !(entity instanceof ExternalIds) ||
 | 
						|
                ((ExternalIds) entity).notationName == null)
 | 
						|
              error("ENTITY values must match the name of an unparsed " +
 | 
						|
                    "entity declared in the DTD");
 | 
						|
          }
 | 
						|
        else if ("NOTATION".equals(decl.type))
 | 
						|
          {
 | 
						|
            if (!decl.values.contains(value))
 | 
						|
              error("NOTATION values must match a declared notation name",
 | 
						|
                    value);
 | 
						|
            // VC: Notation Attributes
 | 
						|
            ExternalIds notation = doctype.getNotation(value);
 | 
						|
            if (notation == null)
 | 
						|
              error("NOTATION values must match the name of a notation " +
 | 
						|
                    "declared in the DTD", value);
 | 
						|
          }
 | 
						|
      }
 | 
						|
    if (namespaceAware)
 | 
						|
      {
 | 
						|
        if (!addNamespace(attr))
 | 
						|
          attrs.add(attr);
 | 
						|
      }
 | 
						|
    else
 | 
						|
      attrs.add(attr);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Determines whether the specified attribute is a namespace declaration,
 | 
						|
   * and adds it to the current namespace context if so. Returns false if
 | 
						|
   * the attribute is an ordinary attribute.
 | 
						|
   */
 | 
						|
  private boolean addNamespace(Attribute attr)
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    if ("xmlns".equals(attr.name))
 | 
						|
      {
 | 
						|
        LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
 | 
						|
        if (ctx.get(XMLConstants.DEFAULT_NS_PREFIX) != null)
 | 
						|
          error("Duplicate default namespace declaration");
 | 
						|
        if (XMLConstants.XML_NS_URI.equals(attr.value))
 | 
						|
          error("can't bind XML namespace");
 | 
						|
        ctx.put(XMLConstants.DEFAULT_NS_PREFIX, attr.value);
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
    else if ("xmlns".equals(attr.prefix))
 | 
						|
      {
 | 
						|
        LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
 | 
						|
        if (ctx.get(attr.localName) != null)
 | 
						|
          error("Duplicate namespace declaration for prefix",
 | 
						|
                attr.localName);
 | 
						|
        if (XMLConstants.XML_NS_PREFIX.equals(attr.localName))
 | 
						|
          {
 | 
						|
            if (!XMLConstants.XML_NS_URI.equals(attr.value))
 | 
						|
              error("can't redeclare xml prefix");
 | 
						|
            else
 | 
						|
              return false; // treat as attribute
 | 
						|
          }
 | 
						|
        if (XMLConstants.XML_NS_URI.equals(attr.value))
 | 
						|
          error("can't bind non-xml prefix to XML namespace");
 | 
						|
        if (XMLConstants.XMLNS_ATTRIBUTE.equals(attr.localName))
 | 
						|
          error("can't redeclare xmlns prefix");
 | 
						|
        if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(attr.value))
 | 
						|
          error("can't bind non-xmlns prefix to XML Namespace namespace");
 | 
						|
        if ("".equals(attr.value) && !input.xml11)
 | 
						|
          error("illegal use of 1.1-style prefix unbinding in 1.0 document");
 | 
						|
        ctx.put(attr.localName, attr.value);
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse a closing tag.
 | 
						|
   */
 | 
						|
  private void readEndElement()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    // pop element off stack
 | 
						|
    String expected = (String) stack.removeLast();
 | 
						|
    require(expected);
 | 
						|
    skipWhitespace();
 | 
						|
    require('>');
 | 
						|
    // Make element name available
 | 
						|
    buf.setLength(0);
 | 
						|
    buf.append(expected);
 | 
						|
    if (validating && doctype != null)
 | 
						|
      endElementValidationHook();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Validate the end of an element.
 | 
						|
   * Called on an end-element or empty element if validating.
 | 
						|
   */
 | 
						|
  private void endElementValidationHook()
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    validateEndElement();
 | 
						|
    validationStack.removeLast();
 | 
						|
    if (stack.isEmpty())
 | 
						|
      currentContentModel = null;
 | 
						|
    else
 | 
						|
      {
 | 
						|
        String parent = (String) stack.getLast();
 | 
						|
        currentContentModel = doctype.getElementModel(parent);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse a comment.
 | 
						|
   */
 | 
						|
  private void readComment(boolean inDTD)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    boolean saved = expandPE;
 | 
						|
    expandPE = false;
 | 
						|
    buf.setLength(0);
 | 
						|
    readUntil(TEST_END_COMMENT);
 | 
						|
    require('>');
 | 
						|
    expandPE = saved;
 | 
						|
    if (inDTD)
 | 
						|
      doctype.addComment(buf.toString());
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse a processing instruction.
 | 
						|
   */
 | 
						|
  private void readPI(boolean inDTD)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    boolean saved = expandPE;
 | 
						|
    expandPE = false;
 | 
						|
    piTarget = readNmtoken(true);
 | 
						|
    if (piTarget.indexOf(':') != -1)
 | 
						|
      error("illegal character in PI target", new Character(':'));
 | 
						|
    if ("xml".equalsIgnoreCase(piTarget))
 | 
						|
      error("illegal PI target", piTarget);
 | 
						|
    if (tryRead(TEST_END_PI))
 | 
						|
      piData = null;
 | 
						|
    else
 | 
						|
      {
 | 
						|
        if (!tryWhitespace())
 | 
						|
          error("whitespace required between PI target and data");
 | 
						|
        buf.setLength(0);
 | 
						|
        readUntil(TEST_END_PI);
 | 
						|
        piData = buf.toString();
 | 
						|
      }
 | 
						|
    expandPE = saved;
 | 
						|
    if (inDTD)
 | 
						|
      doctype.addPI(piTarget, piData);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse an entity reference.
 | 
						|
   */
 | 
						|
  private void readReference()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    buf.setLength(0);
 | 
						|
    String entityName = readNmtoken(true);
 | 
						|
    require(';');
 | 
						|
    buf.setLength(0);
 | 
						|
    buf.append(entityName);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Read an CDATA section.
 | 
						|
   */
 | 
						|
  private void readCDSect()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    buf.setLength(0);
 | 
						|
    readUntil(TEST_END_CDATA);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Read character data.
 | 
						|
   * @return the type of text read (CHARACTERS or SPACE)
 | 
						|
   */
 | 
						|
  private int readCharData(String prefix)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    boolean white = true;
 | 
						|
    buf.setLength(0);
 | 
						|
    if (prefix != null)
 | 
						|
      buf.append(prefix);
 | 
						|
    boolean done = false;
 | 
						|
    boolean entities = false;
 | 
						|
    while (!done)
 | 
						|
      {
 | 
						|
        // Block read
 | 
						|
        mark(tmpBuf.length);
 | 
						|
        int len = read(tmpBuf, 0, tmpBuf.length);
 | 
						|
        if (len == -1)
 | 
						|
          {
 | 
						|
            if (inputStack.size() > 1)
 | 
						|
              {
 | 
						|
                popInput();
 | 
						|
                // report end-entity
 | 
						|
                done = true;
 | 
						|
              }
 | 
						|
            else
 | 
						|
              throw new EOFException();
 | 
						|
          }
 | 
						|
        for (int i = 0; i < len && !done; i++)
 | 
						|
          {
 | 
						|
            int c = tmpBuf[i];
 | 
						|
            switch (c)
 | 
						|
              {
 | 
						|
              case 0x20:
 | 
						|
              case 0x09:
 | 
						|
              case 0x0a:
 | 
						|
              case 0x0d:
 | 
						|
                buf.append(Character.toChars(c));
 | 
						|
                break; // whitespace
 | 
						|
              case 0x26: // '&'
 | 
						|
                reset();
 | 
						|
                read(tmpBuf, 0, i);
 | 
						|
                // character reference?
 | 
						|
                mark(3);
 | 
						|
                c = readCh(); // &
 | 
						|
                c = readCh();
 | 
						|
                if (c == 0x23) // '#'
 | 
						|
                  {
 | 
						|
                    mark(1);
 | 
						|
                    c = readCh();
 | 
						|
                    boolean hex = (c == 0x78); // 'x'
 | 
						|
                    if (!hex)
 | 
						|
                      reset();
 | 
						|
                    char[] ch = readCharacterRef(hex ? 16 : 10);
 | 
						|
                    buf.append(ch, 0, ch.length);
 | 
						|
                    for (int j = 0; j < ch.length; j++)
 | 
						|
                      {
 | 
						|
                        switch (ch[j])
 | 
						|
                          {
 | 
						|
                          case 0x20:
 | 
						|
                          case 0x09:
 | 
						|
                          case 0x0a:
 | 
						|
                          case 0x0d:
 | 
						|
                            break; // whitespace
 | 
						|
                          default:
 | 
						|
                            white = false;
 | 
						|
                          }
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  {
 | 
						|
                    // entity reference
 | 
						|
                    reset();
 | 
						|
                    c = readCh(); // &
 | 
						|
                    String entityName = readNmtoken(true);
 | 
						|
                    require(';');
 | 
						|
                    String text =
 | 
						|
                      (String) PREDEFINED_ENTITIES.get(entityName);
 | 
						|
                    if (text != null)
 | 
						|
                      buf.append(text);
 | 
						|
                    else
 | 
						|
                      {
 | 
						|
                        pushInput("", "&" + entityName + ";", false, false);
 | 
						|
                        done = true;
 | 
						|
                        break;
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
                // continue processing
 | 
						|
                i = -1;
 | 
						|
                mark(tmpBuf.length);
 | 
						|
                len = read(tmpBuf, 0, tmpBuf.length);
 | 
						|
                if (len == -1)
 | 
						|
                  {
 | 
						|
                    if (inputStack.size() > 1)
 | 
						|
                      {
 | 
						|
                        popInput();
 | 
						|
                        done = true;
 | 
						|
                      }
 | 
						|
                    else
 | 
						|
                      throw new EOFException();
 | 
						|
                  }
 | 
						|
                entities = true;
 | 
						|
                break; // end of text sequence
 | 
						|
              case 0x3e: // '>'
 | 
						|
                int l = buf.length();
 | 
						|
                if (l > 1 &&
 | 
						|
                    buf.charAt(l - 1) == ']' &&
 | 
						|
                    buf.charAt(l - 2) == ']')
 | 
						|
                  error("Character data may not contain unescaped ']]>'");
 | 
						|
                buf.append(Character.toChars(c));
 | 
						|
                break;
 | 
						|
              case 0x3c: // '<'
 | 
						|
                reset();
 | 
						|
                // read i characters
 | 
						|
                int count = 0, remaining = i;
 | 
						|
                do
 | 
						|
                  {
 | 
						|
                    int r = read(tmpBuf, 0, remaining);
 | 
						|
                    count += r;
 | 
						|
                    remaining -= r;
 | 
						|
                  }
 | 
						|
                while (count < i);
 | 
						|
                i = len;
 | 
						|
                if (coalescing && tryRead(TEST_CDATA))
 | 
						|
                  readUntil(TEST_END_CDATA); // read CDATA section into buf
 | 
						|
                else
 | 
						|
                  done = true; // end of text sequence
 | 
						|
                break;
 | 
						|
              default:
 | 
						|
                if (input.xml11)
 | 
						|
                  {
 | 
						|
                    if (!isXML11Char(c) || isXML11RestrictedChar(c))
 | 
						|
                      error("illegal XML 1.1 character",
 | 
						|
                            "U+" + Integer.toHexString(c));
 | 
						|
                  }
 | 
						|
                else if (!isChar(c))
 | 
						|
                  error("illegal XML character",
 | 
						|
                        "U+" + Integer.toHexString(c));
 | 
						|
                white = false;
 | 
						|
                buf.append(Character.toChars(c));
 | 
						|
              }
 | 
						|
          }
 | 
						|
        // if text buffer >= 2MB, return it as a chunk
 | 
						|
        // to avoid excessive memory use
 | 
						|
        if (buf.length() >= 2097152)
 | 
						|
          done = true;
 | 
						|
      }
 | 
						|
    if (entities)
 | 
						|
      normalizeCRLF(buf);
 | 
						|
    return white ? XMLStreamConstants.SPACE : XMLStreamConstants.CHARACTERS;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Expands the specified entity.
 | 
						|
   */
 | 
						|
  private void expandEntity(String name, boolean inAttr, boolean normalize)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    if (doctype != null)
 | 
						|
      {
 | 
						|
        Object value = doctype.getEntity(name);
 | 
						|
        if (value != null)
 | 
						|
          {
 | 
						|
            if (xmlStandalone == Boolean.TRUE)
 | 
						|
              {
 | 
						|
                // VC: Standalone Document Declaration
 | 
						|
                if (doctype.isEntityExternal(name))
 | 
						|
                  error("reference to external entity in standalone document");
 | 
						|
                else if (value instanceof ExternalIds)
 | 
						|
                  {
 | 
						|
                    ExternalIds ids = (ExternalIds) value;
 | 
						|
                    if (ids.notationName != null &&
 | 
						|
                        doctype.isNotationExternal(ids.notationName))
 | 
						|
                      error("reference to external notation in " +
 | 
						|
                            "standalone document");
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            if (value instanceof String)
 | 
						|
              {
 | 
						|
                String text = (String) value;
 | 
						|
                if (inAttr && text.indexOf('<') != -1)
 | 
						|
                  error("< in attribute value");
 | 
						|
                pushInput(name, text, !inAttr, normalize);
 | 
						|
              }
 | 
						|
            else if (inAttr)
 | 
						|
              error("reference to external entity in attribute value", name);
 | 
						|
            else
 | 
						|
              pushInput(name, (ExternalIds) value, !inAttr, normalize);
 | 
						|
            return;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    error("reference to undeclared entity", name);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates whether the specified entity is unparsed.
 | 
						|
   */
 | 
						|
  private boolean isUnparsedEntity(String name)
 | 
						|
  {
 | 
						|
    if (doctype != null)
 | 
						|
      {
 | 
						|
        Object value = doctype.getEntity(name);
 | 
						|
        if (value != null && value instanceof ExternalIds)
 | 
						|
          return ((ExternalIds) value).notationName != null;
 | 
						|
      }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Read an equals sign.
 | 
						|
   */
 | 
						|
  private void readEq()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    skipWhitespace();
 | 
						|
    require('=');
 | 
						|
    skipWhitespace();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Character read for reading literals.
 | 
						|
   * @param recognizePEs whether to recognize parameter-entity references
 | 
						|
   */
 | 
						|
  private int literalReadCh(boolean recognizePEs)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    int c = recognizePEs ? readCh() : read();
 | 
						|
    while (c == -1)
 | 
						|
      {
 | 
						|
        if (inputStack.size() > 1)
 | 
						|
          {
 | 
						|
            inputStack.removeLast();
 | 
						|
            input = (Input) inputStack.getLast();
 | 
						|
            // Don't issue end-entity
 | 
						|
            c = recognizePEs ? readCh() : read();
 | 
						|
          }
 | 
						|
        else
 | 
						|
          throw new EOFException();
 | 
						|
      }
 | 
						|
    return c;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Read a string literal.
 | 
						|
   */
 | 
						|
  private String readLiteral(int flags, boolean recognizePEs)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    boolean saved = expandPE;
 | 
						|
    int delim = readCh();
 | 
						|
    if (delim != 0x27 && delim != 0x22)
 | 
						|
      error("expected '\"' or \"'\"", "U+" + Integer.toHexString(delim));
 | 
						|
    literalBuf.setLength(0);
 | 
						|
    if ((flags & LIT_DISABLE_PE) != 0)
 | 
						|
      expandPE = false;
 | 
						|
    boolean entities = false;
 | 
						|
    int inputStackSize = inputStack.size();
 | 
						|
    do
 | 
						|
      {
 | 
						|
        int c = literalReadCh(recognizePEs);
 | 
						|
        if (c == delim && inputStackSize == inputStack.size())
 | 
						|
          break;
 | 
						|
        switch (c)
 | 
						|
          {
 | 
						|
          case 0x0a:
 | 
						|
          case 0x0d:
 | 
						|
            if ((flags & (LIT_ATTRIBUTE | LIT_PUBID)) != 0)
 | 
						|
              c = 0x20; // normalize to space
 | 
						|
            break;
 | 
						|
          case 0x09:
 | 
						|
            if ((flags & LIT_ATTRIBUTE) != 0)
 | 
						|
              c = 0x20; // normalize to space
 | 
						|
            break;
 | 
						|
          case 0x26: // '&'
 | 
						|
            mark(2);
 | 
						|
            c = readCh();
 | 
						|
            if (c == 0x23) // '#'
 | 
						|
              {
 | 
						|
                if ((flags & LIT_DISABLE_CREF) != 0)
 | 
						|
                  {
 | 
						|
                    reset();
 | 
						|
                    c = 0x26; // '&'
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  {
 | 
						|
                    mark(1);
 | 
						|
                    c = readCh();
 | 
						|
                    boolean hex = (c == 0x78); // 'x'
 | 
						|
                    if (!hex)
 | 
						|
                      reset();
 | 
						|
                    char[] ref = readCharacterRef(hex ? 16 : 10);
 | 
						|
                    for (int i = 0; i < ref.length; i++)
 | 
						|
                      literalBuf.append(ref[i]);
 | 
						|
                    entities = true;
 | 
						|
                    continue;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                if ((flags & LIT_DISABLE_EREF) != 0)
 | 
						|
                  {
 | 
						|
                    reset();
 | 
						|
                    c = 0x26; // '&'
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  {
 | 
						|
                    reset();
 | 
						|
                    String entityName = readNmtoken(true);
 | 
						|
                    require(';');
 | 
						|
                    String text =
 | 
						|
                      (String) PREDEFINED_ENTITIES.get(entityName);
 | 
						|
                    if (text != null)
 | 
						|
                      literalBuf.append(text);
 | 
						|
                    else
 | 
						|
                      expandEntity(entityName,
 | 
						|
                                   (flags & LIT_ATTRIBUTE) != 0,
 | 
						|
                                   true);
 | 
						|
                    entities = true;
 | 
						|
                    continue;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            break;
 | 
						|
          case 0x3c: // '<'
 | 
						|
            if ((flags & LIT_ATTRIBUTE) != 0)
 | 
						|
              error("attribute values may not contain '<'");
 | 
						|
            break;
 | 
						|
          case -1:
 | 
						|
            if (inputStack.size() > 1)
 | 
						|
              {
 | 
						|
                popInput();
 | 
						|
                continue;
 | 
						|
              }
 | 
						|
            throw new EOFException();
 | 
						|
          default:
 | 
						|
            if ((c < 0x0020 || c > 0xfffd) ||
 | 
						|
                (c >= 0xd800 && c < 0xdc00) ||
 | 
						|
                (input.xml11 && (c >= 0x007f) &&
 | 
						|
                 (c <= 0x009f) && (c != 0x0085)))
 | 
						|
              error("illegal character", "U+" + Integer.toHexString(c));
 | 
						|
          }
 | 
						|
        literalBuf.append(Character.toChars(c));
 | 
						|
      }
 | 
						|
    while (true);
 | 
						|
    expandPE = saved;
 | 
						|
    if (entities)
 | 
						|
      normalizeCRLF(literalBuf);
 | 
						|
    if ((flags & LIT_NORMALIZE) > 0)
 | 
						|
      literalBuf = normalize(literalBuf);
 | 
						|
    return literalBuf.toString();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Performs attribute-value normalization of the text buffer.
 | 
						|
   * This discards leading and trailing whitespace, and replaces sequences
 | 
						|
   * of whitespace with a single space.
 | 
						|
   */
 | 
						|
  private StringBuffer normalize(StringBuffer buf)
 | 
						|
  {
 | 
						|
    StringBuffer acc = new StringBuffer();
 | 
						|
    int len = buf.length();
 | 
						|
    int avState = 0;
 | 
						|
    for (int i = 0; i < len; i++)
 | 
						|
      {
 | 
						|
        char c = buf.charAt(i);
 | 
						|
        if (c == ' ')
 | 
						|
          avState = (avState == 0) ? 0 : 1;
 | 
						|
        else
 | 
						|
          {
 | 
						|
            if (avState == 1)
 | 
						|
              acc.append(' ');
 | 
						|
            acc.append(c);
 | 
						|
            avState = 2;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return acc;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Replace any CR/LF pairs in the buffer with LF.
 | 
						|
   * This may be necessary if combinations of CR or LF were declared as
 | 
						|
   * (character) entity references in the input.
 | 
						|
   */
 | 
						|
  private void normalizeCRLF(StringBuffer buf)
 | 
						|
  {
 | 
						|
    int len = buf.length() - 1;
 | 
						|
    for (int i = 0; i < len; i++)
 | 
						|
      {
 | 
						|
        char c = buf.charAt(i);
 | 
						|
        if (c == '\r' && buf.charAt(i + 1) == '\n')
 | 
						|
          {
 | 
						|
            buf.deleteCharAt(i--);
 | 
						|
            len--;
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse and expand a parameter entity reference.
 | 
						|
   */
 | 
						|
  private void expandPEReference()
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    String name = readNmtoken(true, new StringBuffer());
 | 
						|
    require(';');
 | 
						|
    mark(1); // ensure we don't reset to before the semicolon
 | 
						|
    if (doctype != null)
 | 
						|
      {
 | 
						|
        String entityName = "%" + name;
 | 
						|
        Object entity = doctype.getEntity(entityName);
 | 
						|
        if (entity != null)
 | 
						|
          {
 | 
						|
            if (xmlStandalone == Boolean.TRUE)
 | 
						|
              {
 | 
						|
                if (doctype.isEntityExternal(entityName))
 | 
						|
                  error("reference to external parameter entity in " +
 | 
						|
                        "standalone document");
 | 
						|
              }
 | 
						|
            if (entity instanceof String)
 | 
						|
              {
 | 
						|
                pushInput(name, (String) entity, false, input.normalize);
 | 
						|
                //pushInput(name, " " + (String) entity + " ");
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                //pushInput("", " ");
 | 
						|
                pushInput(name, (ExternalIds) entity, false, input.normalize);
 | 
						|
                //pushInput("", " ");
 | 
						|
              }
 | 
						|
          }
 | 
						|
        else
 | 
						|
          error("reference to undeclared parameter entity", name);
 | 
						|
      }
 | 
						|
    else
 | 
						|
      error("reference to parameter entity without doctype", name);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse the digits in a character reference.
 | 
						|
   * @param base the base of the digits (10 or 16)
 | 
						|
   */
 | 
						|
  private char[] readCharacterRef(int base)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    CPStringBuilder b = new CPStringBuilder();
 | 
						|
    for (int c = readCh(); c != 0x3b && c != -1; c = readCh())
 | 
						|
      b.append(Character.toChars(c));
 | 
						|
    try
 | 
						|
      {
 | 
						|
        int ord = Integer.parseInt(b.toString(), base);
 | 
						|
        if (input.xml11)
 | 
						|
          {
 | 
						|
            if (!isXML11Char(ord))
 | 
						|
              error("illegal XML 1.1 character reference " +
 | 
						|
                    "U+" + Integer.toHexString(ord));
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            if ((ord < 0x20 && !(ord == 0x0a || ord == 0x09 || ord == 0x0d))
 | 
						|
                || (ord >= 0xd800 && ord <= 0xdfff)
 | 
						|
                || ord == 0xfffe || ord == 0xffff
 | 
						|
                || ord > 0x0010ffff)
 | 
						|
              error("illegal XML character reference " +
 | 
						|
                    "U+" + Integer.toHexString(ord));
 | 
						|
          }
 | 
						|
        return Character.toChars(ord);
 | 
						|
      }
 | 
						|
    catch (NumberFormatException e)
 | 
						|
      {
 | 
						|
        error("illegal characters in character reference", b.toString());
 | 
						|
        return null;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parses an NMTOKEN or Name production.
 | 
						|
   * @param isName if a Name, otherwise an NMTOKEN
 | 
						|
   */
 | 
						|
  private String readNmtoken(boolean isName)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    return readNmtoken(isName, nmtokenBuf);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parses an NMTOKEN or Name production using the specified buffer.
 | 
						|
   * @param isName if a Name, otherwise an NMTOKEN
 | 
						|
   * @param buf the character buffer to use
 | 
						|
   */
 | 
						|
  private String readNmtoken(boolean isName, StringBuffer buf)
 | 
						|
    throws IOException, XMLStreamException
 | 
						|
  {
 | 
						|
    buf.setLength(0);
 | 
						|
    int c = readCh();
 | 
						|
    if (isName)
 | 
						|
      {
 | 
						|
        if (!isNameStartCharacter(c, input.xml11))
 | 
						|
          error("not a name start character",
 | 
						|
                "U+" + Integer.toHexString(c));
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        if (!isNameCharacter(c, input.xml11))
 | 
						|
          error("not a name character",
 | 
						|
                "U+" + Integer.toHexString(c));
 | 
						|
      }
 | 
						|
    buf.append(Character.toChars(c));
 | 
						|
    do
 | 
						|
      {
 | 
						|
        mark(1);
 | 
						|
        c = readCh();
 | 
						|
        switch (c)
 | 
						|
          {
 | 
						|
          case 0x25: // '%'
 | 
						|
          case 0x3c: // '<'
 | 
						|
          case 0x3e: // '>'
 | 
						|
          case 0x26: // '&'
 | 
						|
          case 0x2c: // ','
 | 
						|
          case 0x7c: // '|'
 | 
						|
          case 0x2a: // '*'
 | 
						|
          case 0x2b: // '+'
 | 
						|
          case 0x3f: // '?'
 | 
						|
          case 0x29: // ')'
 | 
						|
          case 0x3d: // '='
 | 
						|
          case 0x27: // '\''
 | 
						|
          case 0x22: // '"'
 | 
						|
          case 0x5b: // '['
 | 
						|
          case 0x20: // ' '
 | 
						|
          case 0x09: // '\t'
 | 
						|
          case 0x0a: // '\n'
 | 
						|
          case 0x0d: // '\r'
 | 
						|
          case 0x3b: // ';'
 | 
						|
          case 0x2f: // '/'
 | 
						|
          case -1:
 | 
						|
            reset();
 | 
						|
            return intern(buf.toString());
 | 
						|
          default:
 | 
						|
            if (!isNameCharacter(c, input.xml11))
 | 
						|
              error("not a name character",
 | 
						|
                    "U+" + Integer.toHexString(c));
 | 
						|
            else
 | 
						|
              buf.append(Character.toChars(c));
 | 
						|
          }
 | 
						|
      }
 | 
						|
    while (true);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates whether the specified Unicode character is an XML 1.1 Char.
 | 
						|
   */
 | 
						|
  public static boolean isXML11Char(int c)
 | 
						|
  {
 | 
						|
    return ((c >= 0x0001 && c <= 0xD7FF) ||
 | 
						|
            (c >= 0xE000 && c < 0xFFFE) ||
 | 
						|
            (c >= 0x10000 && c <= 0x10FFFF));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates whether the specified Unicode character is an XML 1.1
 | 
						|
   * RestrictedChar.
 | 
						|
   */
 | 
						|
  public static boolean isXML11RestrictedChar(int c)
 | 
						|
  {
 | 
						|
    return ((c >= 0x0001 && c <= 0x0008) ||
 | 
						|
            (c >= 0x000B && c <= 0x000C) ||
 | 
						|
            (c >= 0x000E && c <= 0x001F) ||
 | 
						|
            (c >= 0x007F && c <= 0x0084) ||
 | 
						|
            (c >= 0x0086 && c <= 0x009F));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates whether the specified text matches the Name or Nmtoken
 | 
						|
   * production.
 | 
						|
   */
 | 
						|
  private boolean isNmtoken(String text, boolean isName)
 | 
						|
  {
 | 
						|
    try
 | 
						|
      {
 | 
						|
        int[] cp = UnicodeReader.toCodePointArray(text);
 | 
						|
        if (cp.length == 0)
 | 
						|
          return false;
 | 
						|
        if (isName)
 | 
						|
          {
 | 
						|
            if (!isNameStartCharacter(cp[0], input.xml11))
 | 
						|
              return false;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            if (!isNameCharacter(cp[0], input.xml11))
 | 
						|
              return false;
 | 
						|
          }
 | 
						|
        for (int i = 1; i < cp.length; i++)
 | 
						|
          {
 | 
						|
            if (!isNameCharacter(cp[i], input.xml11))
 | 
						|
              return false;
 | 
						|
          }
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
    catch (IOException e)
 | 
						|
      {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates whether the specified Unicode character is a Name start
 | 
						|
   * character.
 | 
						|
   */
 | 
						|
  public static boolean isNameStartCharacter(int c, boolean xml11)
 | 
						|
  {
 | 
						|
    if (xml11)
 | 
						|
      return ((c >= 0x0041 && c <= 0x005a) ||
 | 
						|
              (c >= 0x0061 && c <= 0x007a) ||
 | 
						|
              c == 0x3a |
 | 
						|
              c == 0x5f |
 | 
						|
              (c >= 0xC0 && c <= 0xD6) ||
 | 
						|
              (c >= 0xD8 && c <= 0xF6) ||
 | 
						|
              (c >= 0xF8 && c <= 0x2FF) ||
 | 
						|
              (c >= 0x370 && c <= 0x37D) ||
 | 
						|
              (c >= 0x37F && c <= 0x1FFF) ||
 | 
						|
              (c >= 0x200C && c <= 0x200D) ||
 | 
						|
              (c >= 0x2070 && c <= 0x218F) ||
 | 
						|
              (c >= 0x2C00 && c <= 0x2FEF) ||
 | 
						|
              (c >= 0x3001 && c <= 0xD7FF) ||
 | 
						|
              (c >= 0xF900 && c <= 0xFDCF) ||
 | 
						|
              (c >= 0xFDF0 && c <= 0xFFFD) ||
 | 
						|
              (c >= 0x10000 && c <= 0xEFFFF));
 | 
						|
    else
 | 
						|
      return (c == 0x5f || c == 0x3a || isLetter(c));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates whether the specified Unicode character is a Name non-initial
 | 
						|
   * character.
 | 
						|
   */
 | 
						|
  public static boolean isNameCharacter(int c, boolean xml11)
 | 
						|
  {
 | 
						|
    if (xml11)
 | 
						|
      return ((c >= 0x0041 && c <= 0x005a) ||
 | 
						|
              (c >= 0x0061 && c <= 0x007a) ||
 | 
						|
              (c >= 0x0030 && c <= 0x0039) ||
 | 
						|
              c == 0x3a |
 | 
						|
              c == 0x5f |
 | 
						|
              c == 0x2d |
 | 
						|
              c == 0x2e |
 | 
						|
              c == 0xB7 |
 | 
						|
              (c >= 0xC0 && c <= 0xD6) ||
 | 
						|
              (c >= 0xD8 && c <= 0xF6) ||
 | 
						|
              (c >= 0xF8 && c <= 0x2FF) ||
 | 
						|
              (c >= 0x300 && c <= 0x37D) ||
 | 
						|
              (c >= 0x37F && c <= 0x1FFF) ||
 | 
						|
              (c >= 0x200C && c <= 0x200D) ||
 | 
						|
              (c >= 0x203F && c <= 0x2040) ||
 | 
						|
              (c >= 0x2070 && c <= 0x218F) ||
 | 
						|
              (c >= 0x2C00 && c <= 0x2FEF) ||
 | 
						|
              (c >= 0x3001 && c <= 0xD7FF) ||
 | 
						|
              (c >= 0xF900 && c <= 0xFDCF) ||
 | 
						|
              (c >= 0xFDF0 && c <= 0xFFFD) ||
 | 
						|
              (c >= 0x10000 && c <= 0xEFFFF));
 | 
						|
    else
 | 
						|
      return (c == 0x2e || c == 0x2d || c == 0x5f || c == 0x3a ||
 | 
						|
              isLetter(c) || isDigit(c) ||
 | 
						|
              isCombiningChar(c) || isExtender(c));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates whether the specified Unicode character matches the Letter
 | 
						|
   * production.
 | 
						|
   */
 | 
						|
  public static boolean isLetter(int c)
 | 
						|
  {
 | 
						|
    if ((c >= 0x0041 && c <= 0x005A) ||
 | 
						|
        (c >= 0x0061 && c <= 0x007A) ||
 | 
						|
        (c >= 0x00C0 && c <= 0x00D6) ||
 | 
						|
        (c >= 0x00D8 && c <= 0x00F6) ||
 | 
						|
        (c >= 0x00F8 && c <= 0x00FF) ||
 | 
						|
        (c >= 0x0100 && c <= 0x0131) ||
 | 
						|
        (c >= 0x0134 && c <= 0x013E) ||
 | 
						|
        (c >= 0x0141 && c <= 0x0148) ||
 | 
						|
        (c >= 0x014A && c <= 0x017E) ||
 | 
						|
        (c >= 0x0180 && c <= 0x01C3) ||
 | 
						|
        (c >= 0x01CD && c <= 0x01F0) ||
 | 
						|
        (c >= 0x01F4 && c <= 0x01F5) ||
 | 
						|
        (c >= 0x01FA && c <= 0x0217) ||
 | 
						|
        (c >= 0x0250 && c <= 0x02A8) ||
 | 
						|
        (c >= 0x02BB && c <= 0x02C1) ||
 | 
						|
        c == 0x0386 ||
 | 
						|
        (c >= 0x0388 && c <= 0x038A) ||
 | 
						|
        c == 0x038C ||
 | 
						|
        (c >= 0x038E && c <= 0x03A1) ||
 | 
						|
        (c >= 0x03A3 && c <= 0x03CE) ||
 | 
						|
        (c >= 0x03D0 && c <= 0x03D6) ||
 | 
						|
        c == 0x03DA ||
 | 
						|
      c == 0x03DC ||
 | 
						|
        c == 0x03DE ||
 | 
						|
        c == 0x03E0 ||
 | 
						|
        (c >= 0x03E2 && c <= 0x03F3) ||
 | 
						|
        (c >= 0x0401 && c <= 0x040C) ||
 | 
						|
        (c >= 0x040E && c <= 0x044F) ||
 | 
						|
        (c >= 0x0451 && c <= 0x045C) ||
 | 
						|
        (c >= 0x045E && c <= 0x0481) ||
 | 
						|
        (c >= 0x0490 && c <= 0x04C4) ||
 | 
						|
        (c >= 0x04C7 && c <= 0x04C8) ||
 | 
						|
        (c >= 0x04CB && c <= 0x04CC) ||
 | 
						|
        (c >= 0x04D0 && c <= 0x04EB) ||
 | 
						|
        (c >= 0x04EE && c <= 0x04F5) ||
 | 
						|
        (c >= 0x04F8 && c <= 0x04F9) ||
 | 
						|
        (c >= 0x0531 && c <= 0x0556) ||
 | 
						|
        c == 0x0559 ||
 | 
						|
        (c >= 0x0561 && c <= 0x0586) ||
 | 
						|
        (c >= 0x05D0 && c <= 0x05EA) ||
 | 
						|
        (c >= 0x05F0 && c <= 0x05F2) ||
 | 
						|
        (c >= 0x0621 && c <= 0x063A) ||
 | 
						|
        (c >= 0x0641 && c <= 0x064A) ||
 | 
						|
        (c >= 0x0671 && c <= 0x06B7) ||
 | 
						|
        (c >= 0x06BA && c <= 0x06BE) ||
 | 
						|
        (c >= 0x06C0 && c <= 0x06CE) ||
 | 
						|
        (c >= 0x06D0 && c <= 0x06D3) ||
 | 
						|
        c == 0x06D5 ||
 | 
						|
        (c >= 0x06E5 && c <= 0x06E6) ||
 | 
						|
        (c >= 0x0905 && c <= 0x0939) ||
 | 
						|
        c == 0x093D ||
 | 
						|
        (c >= 0x0958 && c <= 0x0961) ||
 | 
						|
        (c >= 0x0985 && c <= 0x098C) ||
 | 
						|
        (c >= 0x098F && c <= 0x0990) ||
 | 
						|
        (c >= 0x0993 && c <= 0x09A8) ||
 | 
						|
        (c >= 0x09AA && c <= 0x09B0) ||
 | 
						|
        c == 0x09B2 ||
 | 
						|
        (c >= 0x09B6 && c <= 0x09B9) ||
 | 
						|
        (c >= 0x09DC && c <= 0x09DD) ||
 | 
						|
        (c >= 0x09DF && c <= 0x09E1) ||
 | 
						|
        (c >= 0x09F0 && c <= 0x09F1) ||
 | 
						|
        (c >= 0x0A05 && c <= 0x0A0A) ||
 | 
						|
        (c >= 0x0A0F && c <= 0x0A10) ||
 | 
						|
        (c >= 0x0A13 && c <= 0x0A28) ||
 | 
						|
        (c >= 0x0A2A && c <= 0x0A30) ||
 | 
						|
        (c >= 0x0A32 && c <= 0x0A33) ||
 | 
						|
        (c >= 0x0A35 && c <= 0x0A36) ||
 | 
						|
        (c >= 0x0A38 && c <= 0x0A39) ||
 | 
						|
        (c >= 0x0A59 && c <= 0x0A5C) ||
 | 
						|
        c == 0x0A5E ||
 | 
						|
        (c >= 0x0A72 && c <= 0x0A74) ||
 | 
						|
        (c >= 0x0A85 && c <= 0x0A8B) ||
 | 
						|
        c == 0x0A8D ||
 | 
						|
        (c >= 0x0A8F && c <= 0x0A91) ||
 | 
						|
        (c >= 0x0A93 && c <= 0x0AA8) ||
 | 
						|
        (c >= 0x0AAA && c <= 0x0AB0) ||
 | 
						|
        (c >= 0x0AB2 && c <= 0x0AB3) ||
 | 
						|
        (c >= 0x0AB5 && c <= 0x0AB9) ||
 | 
						|
        c == 0x0ABD ||
 | 
						|
        c == 0x0AE0 ||
 | 
						|
        (c >= 0x0B05 && c <= 0x0B0C) ||
 | 
						|
        (c >= 0x0B0F && c <= 0x0B10) ||
 | 
						|
        (c >= 0x0B13 && c <= 0x0B28) ||
 | 
						|
        (c >= 0x0B2A && c <= 0x0B30) ||
 | 
						|
        (c >= 0x0B32 && c <= 0x0B33) ||
 | 
						|
        (c >= 0x0B36 && c <= 0x0B39) ||
 | 
						|
        c == 0x0B3D ||
 | 
						|
        (c >= 0x0B5C && c <= 0x0B5D) ||
 | 
						|
        (c >= 0x0B5F && c <= 0x0B61) ||
 | 
						|
        (c >= 0x0B85 && c <= 0x0B8A) ||
 | 
						|
        (c >= 0x0B8E && c <= 0x0B90) ||
 | 
						|
        (c >= 0x0B92 && c <= 0x0B95) ||
 | 
						|
        (c >= 0x0B99 && c <= 0x0B9A) ||
 | 
						|
        c == 0x0B9C ||
 | 
						|
        (c >= 0x0B9E && c <= 0x0B9F) ||
 | 
						|
        (c >= 0x0BA3 && c <= 0x0BA4) ||
 | 
						|
        (c >= 0x0BA8 && c <= 0x0BAA) ||
 | 
						|
        (c >= 0x0BAE && c <= 0x0BB5) ||
 | 
						|
        (c >= 0x0BB7 && c <= 0x0BB9) ||
 | 
						|
        (c >= 0x0C05 && c <= 0x0C0C) ||
 | 
						|
        (c >= 0x0C0E && c <= 0x0C10) ||
 | 
						|
        (c >= 0x0C12 && c <= 0x0C28) ||
 | 
						|
        (c >= 0x0C2A && c <= 0x0C33) ||
 | 
						|
        (c >= 0x0C35 && c <= 0x0C39) ||
 | 
						|
        (c >= 0x0C60 && c <= 0x0C61) ||
 | 
						|
        (c >= 0x0C85 && c <= 0x0C8C) ||
 | 
						|
        (c >= 0x0C8E && c <= 0x0C90) ||
 | 
						|
        (c >= 0x0C92 && c <= 0x0CA8) ||
 | 
						|
        (c >= 0x0CAA && c <= 0x0CB3) ||
 | 
						|
        (c >= 0x0CB5 && c <= 0x0CB9) ||
 | 
						|
        c == 0x0CDE ||
 | 
						|
        (c >= 0x0CE0 && c <= 0x0CE1) ||
 | 
						|
        (c >= 0x0D05 && c <= 0x0D0C) ||
 | 
						|
        (c >= 0x0D0E && c <= 0x0D10) ||
 | 
						|
        (c >= 0x0D12 && c <= 0x0D28) ||
 | 
						|
        (c >= 0x0D2A && c <= 0x0D39) ||
 | 
						|
        (c >= 0x0D60 && c <= 0x0D61) ||
 | 
						|
        (c >= 0x0E01 && c <= 0x0E2E) ||
 | 
						|
        c == 0x0E30 ||
 | 
						|
        (c >= 0x0E32 && c <= 0x0E33) ||
 | 
						|
        (c >= 0x0E40 && c <= 0x0E45) ||
 | 
						|
        (c >= 0x0E81 && c <= 0x0E82) ||
 | 
						|
        c == 0x0E84 ||
 | 
						|
        (c >= 0x0E87 && c <= 0x0E88) ||
 | 
						|
        c == 0x0E8A ||
 | 
						|
        c == 0x0E8D ||
 | 
						|
        (c >= 0x0E94 && c <= 0x0E97) ||
 | 
						|
        (c >= 0x0E99 && c <= 0x0E9F) ||
 | 
						|
        (c >= 0x0EA1 && c <= 0x0EA3) ||
 | 
						|
        c == 0x0EA5 ||
 | 
						|
        c == 0x0EA7 ||
 | 
						|
        (c >= 0x0EAA && c <= 0x0EAB) ||
 | 
						|
        (c >= 0x0EAD && c <= 0x0EAE) ||
 | 
						|
        c == 0x0EB0 ||
 | 
						|
        (c >= 0x0EB2 && c <= 0x0EB3) ||
 | 
						|
        c == 0x0EBD ||
 | 
						|
        (c >= 0x0EC0 && c <= 0x0EC4) ||
 | 
						|
        (c >= 0x0F40 && c <= 0x0F47) ||
 | 
						|
        (c >= 0x0F49 && c <= 0x0F69) ||
 | 
						|
        (c >= 0x10A0 && c <= 0x10C5) ||
 | 
						|
        (c >= 0x10D0 && c <= 0x10F6) ||
 | 
						|
        c == 0x1100 ||
 | 
						|
        (c >= 0x1102 && c <= 0x1103) ||
 | 
						|
        (c >= 0x1105 && c <= 0x1107) ||
 | 
						|
        c == 0x1109 ||
 | 
						|
        (c >= 0x110B && c <= 0x110C) ||
 | 
						|
        (c >= 0x110E && c <= 0x1112) ||
 | 
						|
        c == 0x113C ||
 | 
						|
        c == 0x113E ||
 | 
						|
        c == 0x1140 ||
 | 
						|
        c == 0x114C ||
 | 
						|
        c == 0x114E ||
 | 
						|
        c == 0x1150 ||
 | 
						|
        (c >= 0x1154 && c <= 0x1155) ||
 | 
						|
        c == 0x1159 ||
 | 
						|
        (c >= 0x115F && c <= 0x1161) ||
 | 
						|
        c == 0x1163 ||
 | 
						|
        c == 0x1165 ||
 | 
						|
        c == 0x1167 ||
 | 
						|
        c == 0x1169 ||
 | 
						|
        (c >= 0x116D && c <= 0x116E) ||
 | 
						|
        (c >= 0x1172 && c <= 0x1173) ||
 | 
						|
        c == 0x1175 ||
 | 
						|
        c == 0x119E ||
 | 
						|
        c == 0x11A8 ||
 | 
						|
        c == 0x11AB ||
 | 
						|
        (c >= 0x11AE && c <= 0x11AF) ||
 | 
						|
        (c >= 0x11B7 && c <= 0x11B8) ||
 | 
						|
        c == 0x11BA ||
 | 
						|
        (c >= 0x11BC && c <= 0x11C2) ||
 | 
						|
        c == 0x11EB ||
 | 
						|
        c == 0x11F0 ||
 | 
						|
        c == 0x11F9 ||
 | 
						|
        (c >= 0x1E00 && c <= 0x1E9B) ||
 | 
						|
        (c >= 0x1EA0 && c <= 0x1EF9) ||
 | 
						|
        (c >= 0x1F00 && c <= 0x1F15) ||
 | 
						|
        (c >= 0x1F18 && c <= 0x1F1D) ||
 | 
						|
        (c >= 0x1F20 && c <= 0x1F45) ||
 | 
						|
        (c >= 0x1F48 && c <= 0x1F4D) ||
 | 
						|
        (c >= 0x1F50 && c <= 0x1F57) ||
 | 
						|
        c == 0x1F59 ||
 | 
						|
        c == 0x1F5B ||
 | 
						|
        c == 0x1F5D ||
 | 
						|
        (c >= 0x1F5F && c <= 0x1F7D) ||
 | 
						|
        (c >= 0x1F80 && c <= 0x1FB4) ||
 | 
						|
        (c >= 0x1FB6 && c <= 0x1FBC) ||
 | 
						|
        c == 0x1FBE ||
 | 
						|
        (c >= 0x1FC2 && c <= 0x1FC4) ||
 | 
						|
        (c >= 0x1FC6 && c <= 0x1FCC) ||
 | 
						|
        (c >= 0x1FD0 && c <= 0x1FD3) ||
 | 
						|
        (c >= 0x1FD6 && c <= 0x1FDB) ||
 | 
						|
        (c >= 0x1FE0 && c <= 0x1FEC) ||
 | 
						|
        (c >= 0x1FF2 && c <= 0x1FF4) ||
 | 
						|
        (c >= 0x1FF6 && c <= 0x1FFC) ||
 | 
						|
        c == 0x2126 ||
 | 
						|
        (c >= 0x212A && c <= 0x212B) ||
 | 
						|
        c == 0x212E ||
 | 
						|
        (c >= 0x2180 && c <= 0x2182) ||
 | 
						|
        (c >= 0x3041 && c <= 0x3094) ||
 | 
						|
        (c >= 0x30A1 && c <= 0x30FA) ||
 | 
						|
        (c >= 0x3105 && c <= 0x312C) ||
 | 
						|
        (c >= 0xAC00 && c <= 0xD7A3))
 | 
						|
        return true; // BaseChar
 | 
						|
    if ((c >= 0x4e00 && c <= 0x9fa5) ||
 | 
						|
        c == 0x3007 ||
 | 
						|
        (c >= 0x3021 && c <= 0x3029))
 | 
						|
      return true; // Ideographic
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates whether the specified Unicode character matches the Digit
 | 
						|
   * production.
 | 
						|
   */
 | 
						|
  public static boolean isDigit(int c)
 | 
						|
  {
 | 
						|
    return ((c >= 0x0030 && c <= 0x0039) ||
 | 
						|
            (c >= 0x0660 && c <= 0x0669) ||
 | 
						|
            (c >= 0x06F0 && c <= 0x06F9) ||
 | 
						|
            (c >= 0x0966 && c <= 0x096F) ||
 | 
						|
            (c >= 0x09E6 && c <= 0x09EF) ||
 | 
						|
            (c >= 0x0A66 && c <= 0x0A6F) ||
 | 
						|
            (c >= 0x0AE6 && c <= 0x0AEF) ||
 | 
						|
            (c >= 0x0B66 && c <= 0x0B6F) ||
 | 
						|
            (c >= 0x0BE7 && c <= 0x0BEF) ||
 | 
						|
            (c >= 0x0C66 && c <= 0x0C6F) ||
 | 
						|
            (c >= 0x0CE6 && c <= 0x0CEF) ||
 | 
						|
            (c >= 0x0D66 && c <= 0x0D6F) ||
 | 
						|
            (c >= 0x0E50 && c <= 0x0E59) ||
 | 
						|
            (c >= 0x0ED0 && c <= 0x0ED9) ||
 | 
						|
            (c >= 0x0F20 && c <= 0x0F29));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates whether the specified Unicode character matches the
 | 
						|
   * CombiningChar production.
 | 
						|
   */
 | 
						|
  public static boolean isCombiningChar(int c)
 | 
						|
  {
 | 
						|
    return ((c >= 0x0300 && c <= 0x0345) ||
 | 
						|
            (c >= 0x0360 && c <= 0x0361) ||
 | 
						|
            (c >= 0x0483 && c <= 0x0486) ||
 | 
						|
            (c >= 0x0591 && c <= 0x05A1) ||
 | 
						|
            (c >= 0x05A3 && c <= 0x05B9) ||
 | 
						|
            (c >= 0x05BB && c <= 0x05BD) ||
 | 
						|
            c == 0x05BF ||
 | 
						|
            (c >= 0x05C1 && c <= 0x05C2) ||
 | 
						|
            c == 0x05C4 ||
 | 
						|
            (c >= 0x064B && c <= 0x0652) ||
 | 
						|
            c == 0x0670 ||
 | 
						|
            (c >= 0x06D6 && c <= 0x06DC) ||
 | 
						|
            (c >= 0x06DD && c <= 0x06DF) ||
 | 
						|
            (c >= 0x06E0 && c <= 0x06E4) ||
 | 
						|
            (c >= 0x06E7 && c <= 0x06E8) ||
 | 
						|
            (c >= 0x06EA && c <= 0x06ED) ||
 | 
						|
            (c >= 0x0901 && c <= 0x0903) ||
 | 
						|
            c == 0x093C ||
 | 
						|
            (c >= 0x093E && c <= 0x094C) ||
 | 
						|
            c == 0x094D ||
 | 
						|
            (c >= 0x0951 && c <= 0x0954) ||
 | 
						|
            (c >= 0x0962 && c <= 0x0963) ||
 | 
						|
            (c >= 0x0981 && c <= 0x0983) ||
 | 
						|
            c == 0x09BC ||
 | 
						|
            c == 0x09BE ||
 | 
						|
            c == 0x09BF ||
 | 
						|
            (c >= 0x09C0 && c <= 0x09C4) ||
 | 
						|
            (c >= 0x09C7 && c <= 0x09C8) ||
 | 
						|
            (c >= 0x09CB && c <= 0x09CD) ||
 | 
						|
            c == 0x09D7 ||
 | 
						|
            (c >= 0x09E2 && c <= 0x09E3) ||
 | 
						|
            c == 0x0A02 ||
 | 
						|
            c == 0x0A3C ||
 | 
						|
            c == 0x0A3E ||
 | 
						|
            c == 0x0A3F ||
 | 
						|
            (c >= 0x0A40 && c <= 0x0A42) ||
 | 
						|
            (c >= 0x0A47 && c <= 0x0A48) ||
 | 
						|
            (c >= 0x0A4B && c <= 0x0A4D) ||
 | 
						|
            (c >= 0x0A70 && c <= 0x0A71) ||
 | 
						|
            (c >= 0x0A81 && c <= 0x0A83) ||
 | 
						|
            c == 0x0ABC ||
 | 
						|
            (c >= 0x0ABE && c <= 0x0AC5) ||
 | 
						|
            (c >= 0x0AC7 && c <= 0x0AC9) ||
 | 
						|
            (c >= 0x0ACB && c <= 0x0ACD) ||
 | 
						|
            (c >= 0x0B01 && c <= 0x0B03) ||
 | 
						|
            c == 0x0B3C ||
 | 
						|
            (c >= 0x0B3E && c <= 0x0B43) ||
 | 
						|
            (c >= 0x0B47 && c <= 0x0B48) ||
 | 
						|
            (c >= 0x0B4B && c <= 0x0B4D) ||
 | 
						|
            (c >= 0x0B56 && c <= 0x0B57) ||
 | 
						|
            (c >= 0x0B82 && c <= 0x0B83) ||
 | 
						|
            (c >= 0x0BBE && c <= 0x0BC2) ||
 | 
						|
            (c >= 0x0BC6 && c <= 0x0BC8) ||
 | 
						|
            (c >= 0x0BCA && c <= 0x0BCD) ||
 | 
						|
            c == 0x0BD7 ||
 | 
						|
            (c >= 0x0C01 && c <= 0x0C03) ||
 | 
						|
            (c >= 0x0C3E && c <= 0x0C44) ||
 | 
						|
            (c >= 0x0C46 && c <= 0x0C48) ||
 | 
						|
            (c >= 0x0C4A && c <= 0x0C4D) ||
 | 
						|
            (c >= 0x0C55 && c <= 0x0C56) ||
 | 
						|
            (c >= 0x0C82 && c <= 0x0C83) ||
 | 
						|
            (c >= 0x0CBE && c <= 0x0CC4) ||
 | 
						|
            (c >= 0x0CC6 && c <= 0x0CC8) ||
 | 
						|
            (c >= 0x0CCA && c <= 0x0CCD) ||
 | 
						|
            (c >= 0x0CD5 && c <= 0x0CD6) ||
 | 
						|
            (c >= 0x0D02 && c <= 0x0D03) ||
 | 
						|
            (c >= 0x0D3E && c <= 0x0D43) ||
 | 
						|
            (c >= 0x0D46 && c <= 0x0D48) ||
 | 
						|
            (c >= 0x0D4A && c <= 0x0D4D) ||
 | 
						|
            c == 0x0D57 ||
 | 
						|
            c == 0x0E31 ||
 | 
						|
            (c >= 0x0E34 && c <= 0x0E3A) ||
 | 
						|
            (c >= 0x0E47 && c <= 0x0E4E) ||
 | 
						|
            c == 0x0EB1 ||
 | 
						|
            (c >= 0x0EB4 && c <= 0x0EB9) ||
 | 
						|
            (c >= 0x0EBB && c <= 0x0EBC) ||
 | 
						|
            (c >= 0x0EC8 && c <= 0x0ECD) ||
 | 
						|
            (c >= 0x0F18 && c <= 0x0F19) ||
 | 
						|
            c == 0x0F35 ||
 | 
						|
            c == 0x0F37 ||
 | 
						|
            c == 0x0F39 ||
 | 
						|
            c == 0x0F3E ||
 | 
						|
            c == 0x0F3F ||
 | 
						|
            (c >= 0x0F71 && c <= 0x0F84) ||
 | 
						|
            (c >= 0x0F86 && c <= 0x0F8B) ||
 | 
						|
            (c >= 0x0F90 && c <= 0x0F95) ||
 | 
						|
            c == 0x0F97 ||
 | 
						|
            (c >= 0x0F99 && c <= 0x0FAD) ||
 | 
						|
            (c >= 0x0FB1 && c <= 0x0FB7) ||
 | 
						|
            c == 0x0FB9 ||
 | 
						|
            (c >= 0x20D0 && c <= 0x20DC) ||
 | 
						|
            c == 0x20E1 ||
 | 
						|
            (c >= 0x302A && c <= 0x302F) ||
 | 
						|
            c == 0x3099 ||
 | 
						|
            c == 0x309A);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates whether the specified Unicode character matches the Extender
 | 
						|
   * production.
 | 
						|
   */
 | 
						|
  public static boolean isExtender(int c)
 | 
						|
  {
 | 
						|
    return (c == 0x00B7 ||
 | 
						|
            c == 0x02D0 ||
 | 
						|
            c == 0x02D1 ||
 | 
						|
            c == 0x0387 ||
 | 
						|
            c == 0x0640 ||
 | 
						|
            c == 0x0E46 ||
 | 
						|
            c == 0x0EC6 ||
 | 
						|
            c == 0x3005 ||
 | 
						|
            (c >= 0x3031 && c <= 0x3035) ||
 | 
						|
            (c >= 0x309D && c <= 0x309E) ||
 | 
						|
            (c >= 0x30FC && c <= 0x30FE));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates whether the specified Unicode character matches the Char
 | 
						|
   * production.
 | 
						|
   */
 | 
						|
  public static boolean isChar(int c)
 | 
						|
  {
 | 
						|
    return (c >= 0x20 && c < 0xd800) ||
 | 
						|
      (c >= 0xe00 && c < 0xfffe) ||
 | 
						|
      (c >= 0x10000 && c < 0x110000) ||
 | 
						|
      c == 0xa || c == 0x9 || c == 0xd;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Interns the specified text or not, depending on the value of
 | 
						|
   * stringInterning.
 | 
						|
   */
 | 
						|
  private String intern(String text)
 | 
						|
  {
 | 
						|
    return stringInterning ? text.intern() : text;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Report a parsing error.
 | 
						|
   */
 | 
						|
  private void error(String message)
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    error(message, null);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Report a parsing error.
 | 
						|
   */
 | 
						|
  private void error(String message, Object info)
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    if (info != null)
 | 
						|
      {
 | 
						|
        if (info instanceof String)
 | 
						|
          message += ": \"" + ((String) info) + "\"";
 | 
						|
        else if (info instanceof Character)
 | 
						|
          message += ": '" + ((Character) info) + "'";
 | 
						|
      }
 | 
						|
    throw new XMLStreamException(message);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Perform validation of a start-element event.
 | 
						|
   */
 | 
						|
  private void validateStartElement(String elementName)
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    if (currentContentModel == null)
 | 
						|
      {
 | 
						|
        // root element
 | 
						|
        // VC: Root Element Type
 | 
						|
        if (!elementName.equals(doctype.rootName))
 | 
						|
          error("root element name must match name in DTD");
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    // VC: Element Valid
 | 
						|
    switch (currentContentModel.type)
 | 
						|
      {
 | 
						|
      case ContentModel.EMPTY:
 | 
						|
        error("child element found in empty element", elementName);
 | 
						|
        break;
 | 
						|
      case ContentModel.ELEMENT:
 | 
						|
        LinkedList ctx = (LinkedList) validationStack.getLast();
 | 
						|
        ctx.add(elementName);
 | 
						|
        break;
 | 
						|
      case ContentModel.MIXED:
 | 
						|
        MixedContentModel mm = (MixedContentModel) currentContentModel;
 | 
						|
        if (!mm.containsName(elementName))
 | 
						|
          error("illegal element for content model", elementName);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Perform validation of an end-element event.
 | 
						|
   */
 | 
						|
  private void validateEndElement()
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    if (currentContentModel == null)
 | 
						|
      {
 | 
						|
        // root element
 | 
						|
        // VC: IDREF
 | 
						|
        if (!idrefs.containsAll(ids))
 | 
						|
          error("IDREF values must match the value of some ID attribute");
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    // VC: Element Valid
 | 
						|
    switch (currentContentModel.type)
 | 
						|
      {
 | 
						|
      case ContentModel.ELEMENT:
 | 
						|
        LinkedList ctx = (LinkedList) validationStack.getLast();
 | 
						|
        ElementContentModel ecm = (ElementContentModel) currentContentModel;
 | 
						|
        validateElementContent(ecm, ctx);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Perform validation of character data.
 | 
						|
   */
 | 
						|
  private void validatePCData(String text)
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    // VC: Element Valid
 | 
						|
    switch (currentContentModel.type)
 | 
						|
      {
 | 
						|
      case ContentModel.EMPTY:
 | 
						|
        error("character data found in empty element", text);
 | 
						|
        break;
 | 
						|
      case ContentModel.ELEMENT:
 | 
						|
        boolean white = true;
 | 
						|
        int len = text.length();
 | 
						|
        for (int i = 0; i < len; i++)
 | 
						|
          {
 | 
						|
            char c = text.charAt(i);
 | 
						|
            if (c != ' ' && c != '\t' && c != '\n' && c != '\r')
 | 
						|
              {
 | 
						|
                white = false;
 | 
						|
                break;
 | 
						|
              }
 | 
						|
          }
 | 
						|
        if (!white)
 | 
						|
          error("character data found in element with element content", text);
 | 
						|
        else if (xmlStandalone == Boolean.TRUE && currentContentModel.external)
 | 
						|
          // VC: Standalone Document Declaration
 | 
						|
          error("whitespace in element content of externally declared " +
 | 
						|
                "element in standalone document");
 | 
						|
        break;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Validates the specified validation context (list of child elements)
 | 
						|
   * against the element content model for the current element.
 | 
						|
   */
 | 
						|
  private void validateElementContent(ElementContentModel model,
 | 
						|
                                      LinkedList children)
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    // Use regular expression
 | 
						|
    CPStringBuilder buf = new CPStringBuilder();
 | 
						|
    for (Iterator i = children.iterator(); i.hasNext(); )
 | 
						|
      {
 | 
						|
        buf.append((String) i.next());
 | 
						|
        buf.append(' ');
 | 
						|
      }
 | 
						|
    String c = buf.toString();
 | 
						|
    String regex = createRegularExpression(model);
 | 
						|
    if (!c.matches(regex))
 | 
						|
      error("element content "+model.text+" does not match expression "+regex, c);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates the regular expression used to validate an element content
 | 
						|
   * model.
 | 
						|
   */
 | 
						|
  private String createRegularExpression(ElementContentModel model)
 | 
						|
  {
 | 
						|
    if (model.regex == null)
 | 
						|
      {
 | 
						|
        CPStringBuilder buf = new CPStringBuilder();
 | 
						|
        buf.append('(');
 | 
						|
        for (Iterator i = model.contentParticles.iterator(); i.hasNext(); )
 | 
						|
          {
 | 
						|
            ContentParticle cp = (ContentParticle) i.next();
 | 
						|
            if (cp.content instanceof String)
 | 
						|
              {
 | 
						|
                buf.append('(');
 | 
						|
                buf.append((String) cp.content);
 | 
						|
                buf.append(' ');
 | 
						|
                buf.append(')');
 | 
						|
                if (cp.max == -1)
 | 
						|
                  {
 | 
						|
                    if (cp.min == 0)
 | 
						|
                      buf.append('*');
 | 
						|
                    else
 | 
						|
                      buf.append('+');
 | 
						|
                  }
 | 
						|
                else if (cp.min == 0)
 | 
						|
                  buf.append('?');
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                ElementContentModel ecm = (ElementContentModel) cp.content;
 | 
						|
                buf.append(createRegularExpression(ecm));
 | 
						|
              }
 | 
						|
            if (model.or && i.hasNext())
 | 
						|
              buf.append('|');
 | 
						|
          }
 | 
						|
        buf.append(')');
 | 
						|
        if (model.max == -1)
 | 
						|
          {
 | 
						|
            if (model.min == 0)
 | 
						|
              buf.append('*');
 | 
						|
            else
 | 
						|
              buf.append('+');
 | 
						|
          }
 | 
						|
        else if (model.min == 0)
 | 
						|
          buf.append('?');
 | 
						|
        model.regex = buf.toString();
 | 
						|
      }
 | 
						|
    return model.regex;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Performs validation of a document type declaration event.
 | 
						|
   */
 | 
						|
  void validateDoctype()
 | 
						|
    throws XMLStreamException
 | 
						|
  {
 | 
						|
    for (Iterator i = doctype.entityIterator(); i.hasNext(); )
 | 
						|
      {
 | 
						|
        Map.Entry entry = (Map.Entry) i.next();
 | 
						|
        Object entity = entry.getValue();
 | 
						|
        if (entity instanceof ExternalIds)
 | 
						|
          {
 | 
						|
            ExternalIds ids = (ExternalIds) entity;
 | 
						|
            if (ids.notationName != null)
 | 
						|
              {
 | 
						|
                // VC: Notation Declared
 | 
						|
                ExternalIds notation = doctype.getNotation(ids.notationName);
 | 
						|
                if (notation == null)
 | 
						|
                  error("Notation name must match the declared name of a " +
 | 
						|
                        "notation", ids.notationName);
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Simple test harness for reading an XML file.
 | 
						|
   * args[0] is the filename of the XML file
 | 
						|
   * If args[1] is "-x", enable XInclude processing
 | 
						|
   */
 | 
						|
  public static void main(String[] args)
 | 
						|
    throws Exception
 | 
						|
  {
 | 
						|
    boolean validating = false;
 | 
						|
    boolean namespaceAware = false;
 | 
						|
    boolean xIncludeAware = false;
 | 
						|
    int pos = 0;
 | 
						|
    while (pos < args.length && args[pos].startsWith("-"))
 | 
						|
      {
 | 
						|
        if ("-x".equals(args[pos]))
 | 
						|
          xIncludeAware = true;
 | 
						|
        else if ("-v".equals(args[pos]))
 | 
						|
          validating = true;
 | 
						|
        else if ("-n".equals(args[pos]))
 | 
						|
          namespaceAware = true;
 | 
						|
        pos++;
 | 
						|
      }
 | 
						|
    if (pos >= args.length)
 | 
						|
      {
 | 
						|
        System.out.println("Syntax: XMLParser [-n] [-v] [-x] <file> [<file2> [...]]");
 | 
						|
        System.out.println("\t-n: use namespace aware mode");
 | 
						|
        System.out.println("\t-v: use validating parser");
 | 
						|
        System.out.println("\t-x: use XInclude aware mode");
 | 
						|
        System.exit(2);
 | 
						|
      }
 | 
						|
    while (pos < args.length)
 | 
						|
      {
 | 
						|
        XMLParser p = new XMLParser(new java.io.FileInputStream(args[pos]),
 | 
						|
                                    absolutize(null, args[pos]),
 | 
						|
                                    validating, // validating
 | 
						|
                                    namespaceAware, // namespaceAware
 | 
						|
                                    true, // coalescing,
 | 
						|
                                    true, // replaceERefs
 | 
						|
                                    true, // externalEntities
 | 
						|
                                    true, // supportDTD
 | 
						|
                                    true, // baseAware
 | 
						|
                                    true, // stringInterning
 | 
						|
                                    true, // extendedEventTypes
 | 
						|
                                    null,
 | 
						|
                                    null);
 | 
						|
        XMLStreamReader reader = p;
 | 
						|
        if (xIncludeAware)
 | 
						|
          reader = new XIncludeFilter(p, args[pos], true, true, true);
 | 
						|
        try
 | 
						|
          {
 | 
						|
            int event;
 | 
						|
            //do
 | 
						|
            while (reader.hasNext())
 | 
						|
              {
 | 
						|
                event = reader.next();
 | 
						|
                Location loc = reader.getLocation();
 | 
						|
                System.out.print(loc.getLineNumber() + ":" +
 | 
						|
                                 loc.getColumnNumber() + " ");
 | 
						|
                switch (event)
 | 
						|
                  {
 | 
						|
                  case XMLStreamConstants.START_DOCUMENT:
 | 
						|
                    System.out.println("START_DOCUMENT version=" +
 | 
						|
                                       reader.getVersion() +
 | 
						|
                                       " encoding=" +
 | 
						|
                                       reader.getEncoding());
 | 
						|
                    break;
 | 
						|
                  case XMLStreamConstants.END_DOCUMENT:
 | 
						|
                    System.out.println("END_DOCUMENT");
 | 
						|
                    break;
 | 
						|
                  case XMLStreamConstants.START_ELEMENT:
 | 
						|
                    System.out.println("START_ELEMENT " +
 | 
						|
                                       reader.getName());
 | 
						|
                    int l = reader.getNamespaceCount();
 | 
						|
                    for (int i = 0; i < l; i++)
 | 
						|
                      System.out.println("\tnamespace " +
 | 
						|
                                         reader.getNamespacePrefix(i) + "='" +
 | 
						|
                                         reader.getNamespaceURI(i)+"'");
 | 
						|
                    l = reader.getAttributeCount();
 | 
						|
                    for (int i = 0; i < l; i++)
 | 
						|
                      System.out.println("\tattribute " +
 | 
						|
                                         reader.getAttributeName(i) + "='" +
 | 
						|
                                         reader.getAttributeValue(i) + "'");
 | 
						|
                    break;
 | 
						|
                  case XMLStreamConstants.END_ELEMENT:
 | 
						|
                    System.out.println("END_ELEMENT " + reader.getName());
 | 
						|
                    break;
 | 
						|
                  case XMLStreamConstants.CHARACTERS:
 | 
						|
                    System.out.println("CHARACTERS '" +
 | 
						|
                                       encodeText(reader.getText()) + "'");
 | 
						|
                    break;
 | 
						|
                  case XMLStreamConstants.CDATA:
 | 
						|
                    System.out.println("CDATA '" +
 | 
						|
                                       encodeText(reader.getText()) + "'");
 | 
						|
                    break;
 | 
						|
                  case XMLStreamConstants.SPACE:
 | 
						|
                    System.out.println("SPACE '" +
 | 
						|
                                       encodeText(reader.getText()) + "'");
 | 
						|
                    break;
 | 
						|
                  case XMLStreamConstants.DTD:
 | 
						|
                    System.out.println("DTD " + reader.getText());
 | 
						|
                    break;
 | 
						|
                  case XMLStreamConstants.ENTITY_REFERENCE:
 | 
						|
                    System.out.println("ENTITY_REFERENCE " + reader.getText());
 | 
						|
                    break;
 | 
						|
                  case XMLStreamConstants.COMMENT:
 | 
						|
                    System.out.println("COMMENT '" +
 | 
						|
                                       encodeText(reader.getText()) + "'");
 | 
						|
                    break;
 | 
						|
                  case XMLStreamConstants.PROCESSING_INSTRUCTION:
 | 
						|
                    System.out.println("PROCESSING_INSTRUCTION " +
 | 
						|
                                       reader.getPITarget() + " " +
 | 
						|
                                       reader.getPIData());
 | 
						|
                    break;
 | 
						|
                  case START_ENTITY:
 | 
						|
                    System.out.println("START_ENTITY " + reader.getText());
 | 
						|
                    break;
 | 
						|
                  case END_ENTITY:
 | 
						|
                    System.out.println("END_ENTITY " + reader.getText());
 | 
						|
                    break;
 | 
						|
                  default:
 | 
						|
                    System.out.println("Unknown event: " + event);
 | 
						|
                  }
 | 
						|
              }
 | 
						|
          }
 | 
						|
        catch (XMLStreamException e)
 | 
						|
          {
 | 
						|
            Location l = reader.getLocation();
 | 
						|
            System.out.println("At line "+l.getLineNumber()+
 | 
						|
                               ", column "+l.getColumnNumber()+
 | 
						|
                               " of "+l.getSystemId());
 | 
						|
            throw e;
 | 
						|
          }
 | 
						|
        pos++;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Escapes control characters in the specified text. For debugging.
 | 
						|
   */
 | 
						|
  private static String encodeText(String text)
 | 
						|
  {
 | 
						|
    CPStringBuilder b = new CPStringBuilder();
 | 
						|
    int len = text.length();
 | 
						|
    for (int i = 0; i < len; i++)
 | 
						|
      {
 | 
						|
        char c = text.charAt(i);
 | 
						|
        switch (c)
 | 
						|
          {
 | 
						|
          case '\t':
 | 
						|
            b.append("\\t");
 | 
						|
            break;
 | 
						|
          case '\n':
 | 
						|
            b.append("\\n");
 | 
						|
            break;
 | 
						|
          case '\r':
 | 
						|
            b.append("\\r");
 | 
						|
            break;
 | 
						|
          default:
 | 
						|
            b.append(c);
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return b.toString();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * An attribute instance.
 | 
						|
   */
 | 
						|
  class Attribute
 | 
						|
  {
 | 
						|
 | 
						|
    /**
 | 
						|
     * Attribute name.
 | 
						|
     */
 | 
						|
    final String name;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Attribute type as declared in the DTD, or CDATA otherwise.
 | 
						|
     */
 | 
						|
    final String type;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Whether the attribute was specified or defaulted.
 | 
						|
     */
 | 
						|
    final boolean specified;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The attribute value.
 | 
						|
     */
 | 
						|
    final String value;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The namespace prefix.
 | 
						|
     */
 | 
						|
    final String prefix;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The namespace local-name.
 | 
						|
     */
 | 
						|
    final String localName;
 | 
						|
 | 
						|
    Attribute(String name, String type, boolean specified, String value)
 | 
						|
    {
 | 
						|
      this.name = name;
 | 
						|
      this.type = type;
 | 
						|
      this.specified = specified;
 | 
						|
      this.value = value;
 | 
						|
      int ci = name.indexOf(':');
 | 
						|
      if (ci == -1)
 | 
						|
        {
 | 
						|
          prefix = null;
 | 
						|
          localName = intern(name);
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          prefix = intern(name.substring(0, ci));
 | 
						|
          localName = intern(name.substring(ci + 1));
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public boolean equals(Object other)
 | 
						|
    {
 | 
						|
      if (other instanceof Attribute)
 | 
						|
        {
 | 
						|
          Attribute a = (Attribute) other;
 | 
						|
          if (namespaceAware)
 | 
						|
            {
 | 
						|
              if (!a.localName.equals(localName))
 | 
						|
                return false;
 | 
						|
              String auri = getNamespaceURI(a.prefix);
 | 
						|
              String uri = getNamespaceURI(prefix);
 | 
						|
              if (uri == null && (auri == null ||
 | 
						|
                                  (input.xml11 && "".equals(auri))))
 | 
						|
               return true;
 | 
						|
              if (uri != null)
 | 
						|
                {
 | 
						|
                  if ("".equals(uri) && input.xml11 && "".equals(auri))
 | 
						|
                    return true;
 | 
						|
                  return uri.equals(auri);
 | 
						|
                }
 | 
						|
              return false;
 | 
						|
            }
 | 
						|
          else
 | 
						|
            return a.name.equals(name);
 | 
						|
        }
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    public String toString()
 | 
						|
    {
 | 
						|
      CPStringBuilder buf = new CPStringBuilder(getClass().getName());
 | 
						|
      buf.append('[');
 | 
						|
      buf.append("name=");
 | 
						|
      buf.append(name);
 | 
						|
      if (value != null)
 | 
						|
        {
 | 
						|
          buf.append(",value=");
 | 
						|
          buf.append(value);
 | 
						|
        }
 | 
						|
      if (type != null)
 | 
						|
        {
 | 
						|
          buf.append(",type=");
 | 
						|
          buf.append(type);
 | 
						|
        }
 | 
						|
      if (specified)
 | 
						|
        buf.append(",specified");
 | 
						|
      buf.append(']');
 | 
						|
      return buf.toString();
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Representation of a DTD.
 | 
						|
   */
 | 
						|
  class Doctype
 | 
						|
  {
 | 
						|
 | 
						|
    /**
 | 
						|
     * Name of the root element.
 | 
						|
     */
 | 
						|
    final String rootName;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Public ID, if any, of external subset.
 | 
						|
     */
 | 
						|
    final String publicId;
 | 
						|
 | 
						|
    /**
 | 
						|
     * System ID (URL), if any, of external subset.
 | 
						|
     */
 | 
						|
    final String systemId;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Map of element names to content models.
 | 
						|
     */
 | 
						|
    private final LinkedHashMap elements = new LinkedHashMap();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Map of element names to maps of attribute declarations.
 | 
						|
     */
 | 
						|
    private final LinkedHashMap attlists = new LinkedHashMap();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Map of entity names to entities (String or ExternalIds).
 | 
						|
     */
 | 
						|
    private final LinkedHashMap entities = new LinkedHashMap();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Map of notation names to ExternalIds.
 | 
						|
     */
 | 
						|
    private final LinkedHashMap notations = new LinkedHashMap();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Map of anonymous keys to comments.
 | 
						|
     */
 | 
						|
    private final LinkedHashMap comments = new LinkedHashMap();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Map of anonymous keys to processing instructions (String[2]
 | 
						|
     * containing {target, data}).
 | 
						|
     */
 | 
						|
    private final LinkedHashMap pis = new LinkedHashMap();
 | 
						|
 | 
						|
    /**
 | 
						|
     * List of keys to all markup entries in the DTD.
 | 
						|
     */
 | 
						|
    private final LinkedList entries = new LinkedList();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set of the entities defined in the external subset.
 | 
						|
     */
 | 
						|
    private final HashSet externalEntities = new HashSet();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set of the notations defined in the external subset.
 | 
						|
     */
 | 
						|
    private final HashSet externalNotations = new HashSet();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Counter for making anonymous keys.
 | 
						|
     */
 | 
						|
    private int anon = 1;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Constructor.
 | 
						|
     */
 | 
						|
    Doctype(String rootName, String publicId, String systemId)
 | 
						|
    {
 | 
						|
      this.rootName = rootName;
 | 
						|
      this.publicId = publicId;
 | 
						|
      this.systemId = systemId;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds an element declaration.
 | 
						|
     * @param name the element name
 | 
						|
     * @param text the content model text
 | 
						|
     * @param model the parsed content model
 | 
						|
     */
 | 
						|
    void addElementDecl(String name, String text, ContentModel model)
 | 
						|
    {
 | 
						|
      if (elements.containsKey(name))
 | 
						|
        return;
 | 
						|
      model.text = text;
 | 
						|
      model.external = (inputStack.size() != 1);
 | 
						|
      elements.put(name, model);
 | 
						|
      entries.add("E" + name);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds an attribute declaration.
 | 
						|
     * @param ename the element name
 | 
						|
     * @param aname the attribute name
 | 
						|
     * @param decl the attribute declaration details
 | 
						|
     */
 | 
						|
    void addAttributeDecl(String ename, String aname, AttributeDecl decl)
 | 
						|
    {
 | 
						|
      LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename);
 | 
						|
      if (attlist == null)
 | 
						|
        {
 | 
						|
          attlist = new LinkedHashMap();
 | 
						|
          attlists.put(ename, attlist);
 | 
						|
        }
 | 
						|
      else if (attlist.containsKey(aname))
 | 
						|
        return;
 | 
						|
      attlist.put(aname, decl);
 | 
						|
      String key = "A" + ename;
 | 
						|
      if (!entries.contains(key))
 | 
						|
        entries.add(key);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds an entity declaration.
 | 
						|
     * @param name the entity name
 | 
						|
     * @param text the entity replacement text
 | 
						|
     * @param inExternalSubset if we are in the exernal subset
 | 
						|
     */
 | 
						|
    void addEntityDecl(String name, String text, boolean inExternalSubset)
 | 
						|
    {
 | 
						|
      if (entities.containsKey(name))
 | 
						|
        return;
 | 
						|
      entities.put(name, text);
 | 
						|
      entries.add("e" + name);
 | 
						|
      if (inExternalSubset)
 | 
						|
        externalEntities.add(name);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds an entity declaration.
 | 
						|
     * @param name the entity name
 | 
						|
     * @param ids the external IDs
 | 
						|
     * @param inExternalSubset if we are in the exernal subset
 | 
						|
     */
 | 
						|
    void addEntityDecl(String name, ExternalIds ids, boolean inExternalSubset)
 | 
						|
    {
 | 
						|
      if (entities.containsKey(name))
 | 
						|
        return;
 | 
						|
      entities.put(name, ids);
 | 
						|
      entries.add("e" + name);
 | 
						|
      if (inExternalSubset)
 | 
						|
        externalEntities.add(name);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds a notation declaration.
 | 
						|
     * @param name the notation name
 | 
						|
     * @param ids the external IDs
 | 
						|
     * @param inExternalSubset if we are in the exernal subset
 | 
						|
     */
 | 
						|
    void addNotationDecl(String name, ExternalIds ids, boolean inExternalSubset)
 | 
						|
    {
 | 
						|
      if (notations.containsKey(name))
 | 
						|
        return;
 | 
						|
      notations.put(name, ids);
 | 
						|
      entries.add("n" + name);
 | 
						|
      if (inExternalSubset)
 | 
						|
        externalNotations.add(name);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds a comment.
 | 
						|
     */
 | 
						|
    void addComment(String text)
 | 
						|
    {
 | 
						|
      String key = Integer.toString(anon++);
 | 
						|
      comments.put(key, text);
 | 
						|
      entries.add("c" + key);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds a processing instruction.
 | 
						|
     */
 | 
						|
    void addPI(String target, String data)
 | 
						|
    {
 | 
						|
      String key = Integer.toString(anon++);
 | 
						|
      pis.put(key, new String[] {target, data});
 | 
						|
      entries.add("p" + key);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the content model for the specified element.
 | 
						|
     * @param name the element name
 | 
						|
     */
 | 
						|
    ContentModel getElementModel(String name)
 | 
						|
    {
 | 
						|
      return (ContentModel) elements.get(name);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the attribute definition for the given attribute
 | 
						|
     * @param ename the element name
 | 
						|
     * @param aname the attribute name
 | 
						|
     */
 | 
						|
    AttributeDecl getAttributeDecl(String ename, String aname)
 | 
						|
    {
 | 
						|
      LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename);
 | 
						|
      return (attlist == null) ? null : (AttributeDecl) attlist.get(aname);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Indicates whether the specified attribute was declared in the DTD.
 | 
						|
     * @param ename the element name
 | 
						|
     * @param aname the attribute name
 | 
						|
     */
 | 
						|
    boolean isAttributeDeclared(String ename, String aname)
 | 
						|
    {
 | 
						|
      LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename);
 | 
						|
      return (attlist == null) ? false : attlist.containsKey(aname);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns an iterator over the entries in the attribute list for the
 | 
						|
     * given element.
 | 
						|
     * @param ename the element name
 | 
						|
     */
 | 
						|
    Iterator attlistIterator(String ename)
 | 
						|
    {
 | 
						|
      LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename);
 | 
						|
      return (attlist == null) ? Collections.EMPTY_LIST.iterator() :
 | 
						|
        attlist.entrySet().iterator();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the entity (String or ExternalIds) for the given entity name.
 | 
						|
     */
 | 
						|
    Object getEntity(String name)
 | 
						|
    {
 | 
						|
      return entities.get(name);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Indicates whether the specified entity was declared in the external
 | 
						|
     * subset.
 | 
						|
     */
 | 
						|
    boolean isEntityExternal(String name)
 | 
						|
    {
 | 
						|
      return externalEntities.contains(name);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns an iterator over the entity map entries.
 | 
						|
     */
 | 
						|
    Iterator entityIterator()
 | 
						|
    {
 | 
						|
      return entities.entrySet().iterator();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the notation IDs for the given notation name.
 | 
						|
     */
 | 
						|
    ExternalIds getNotation(String name)
 | 
						|
    {
 | 
						|
      return (ExternalIds) notations.get(name);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Indicates whether the specified notation was declared in the external
 | 
						|
     * subset.
 | 
						|
     */
 | 
						|
    boolean isNotationExternal(String name)
 | 
						|
    {
 | 
						|
      return externalNotations.contains(name);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the comment associated with the specified (anonymous) key.
 | 
						|
     */
 | 
						|
    String getComment(String key)
 | 
						|
    {
 | 
						|
      return (String) comments.get(key);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the processing instruction associated with the specified
 | 
						|
     * (anonymous) key.
 | 
						|
     */
 | 
						|
    String[] getPI(String key)
 | 
						|
    {
 | 
						|
      return (String[]) pis.get(key);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns an iterator over the keys of the markup entries in this DTD,
 | 
						|
     * in the order declared.
 | 
						|
     */
 | 
						|
    Iterator entryIterator()
 | 
						|
    {
 | 
						|
      return entries.iterator();
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Combination of an ExternalID and an optional NDataDecl.
 | 
						|
   */
 | 
						|
  class ExternalIds
 | 
						|
  {
 | 
						|
 | 
						|
    /**
 | 
						|
     * The public ID.
 | 
						|
     */
 | 
						|
    String publicId;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The system ID.
 | 
						|
     */
 | 
						|
    String systemId;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The notation name declared with the NDATA keyword.
 | 
						|
     */
 | 
						|
    String notationName;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * A content model.
 | 
						|
   */
 | 
						|
  abstract class ContentModel
 | 
						|
  {
 | 
						|
    static final int EMPTY = 0;
 | 
						|
    static final int ANY = 1;
 | 
						|
    static final int ELEMENT = 2;
 | 
						|
    static final int MIXED = 3;
 | 
						|
 | 
						|
    int min;
 | 
						|
    int max;
 | 
						|
    final int type;
 | 
						|
    String text;
 | 
						|
    boolean external;
 | 
						|
 | 
						|
    ContentModel(int type)
 | 
						|
    {
 | 
						|
      this.type = type;
 | 
						|
      min = 1;
 | 
						|
      max = 1;
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * The EMPTY content model.
 | 
						|
   */
 | 
						|
  class EmptyContentModel
 | 
						|
    extends ContentModel
 | 
						|
  {
 | 
						|
 | 
						|
    EmptyContentModel()
 | 
						|
    {
 | 
						|
      super(ContentModel.EMPTY);
 | 
						|
      min = 0;
 | 
						|
      max = 0;
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * The ANY content model.
 | 
						|
   */
 | 
						|
  class AnyContentModel
 | 
						|
    extends ContentModel
 | 
						|
  {
 | 
						|
 | 
						|
    AnyContentModel()
 | 
						|
    {
 | 
						|
      super(ContentModel.ANY);
 | 
						|
      min = 0;
 | 
						|
      max = -1;
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * An element content model.
 | 
						|
   */
 | 
						|
  class ElementContentModel
 | 
						|
    extends ContentModel
 | 
						|
  {
 | 
						|
 | 
						|
    LinkedList contentParticles;
 | 
						|
    boolean or;
 | 
						|
    String regex; // regular expression cache
 | 
						|
 | 
						|
    ElementContentModel()
 | 
						|
    {
 | 
						|
      super(ContentModel.ELEMENT);
 | 
						|
      contentParticles = new LinkedList();
 | 
						|
    }
 | 
						|
 | 
						|
    void addContentParticle(ContentParticle cp)
 | 
						|
    {
 | 
						|
      contentParticles.add(cp);
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  class ContentParticle
 | 
						|
  {
 | 
						|
 | 
						|
    int min = 1;
 | 
						|
    int max = 1;
 | 
						|
    Object content; // Name (String) or ElementContentModel
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * A mixed content model.
 | 
						|
   */
 | 
						|
  class MixedContentModel
 | 
						|
    extends ContentModel
 | 
						|
  {
 | 
						|
 | 
						|
    private HashSet names;
 | 
						|
 | 
						|
    MixedContentModel()
 | 
						|
    {
 | 
						|
      super(ContentModel.MIXED);
 | 
						|
      names = new HashSet();
 | 
						|
    }
 | 
						|
 | 
						|
    void addName(String name)
 | 
						|
    {
 | 
						|
      names.add(name);
 | 
						|
    }
 | 
						|
 | 
						|
    boolean containsName(String name)
 | 
						|
    {
 | 
						|
      return names.contains(name);
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * An attribute definition.
 | 
						|
   */
 | 
						|
  class AttributeDecl
 | 
						|
  {
 | 
						|
 | 
						|
    /**
 | 
						|
     * The attribute type (CDATA, ID, etc).
 | 
						|
     */
 | 
						|
    final String type;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The default value.
 | 
						|
     */
 | 
						|
    final String value;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The value type (#FIXED, #IMPLIED, etc).
 | 
						|
     */
 | 
						|
    final int valueType;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The enumeration text.
 | 
						|
     */
 | 
						|
    final String enumeration;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The enumeration tokens.
 | 
						|
     */
 | 
						|
    final HashSet values;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Whether this attribute declaration occurred in the external subset.
 | 
						|
     */
 | 
						|
    final boolean external;
 | 
						|
 | 
						|
    AttributeDecl(String type, String value,
 | 
						|
                  int valueType, String enumeration,
 | 
						|
                  HashSet values, boolean external)
 | 
						|
    {
 | 
						|
      this.type = type;
 | 
						|
      this.value = value;
 | 
						|
      this.valueType = valueType;
 | 
						|
      this.enumeration = enumeration;
 | 
						|
      this.values = values;
 | 
						|
      this.external = external;
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * An XML input source.
 | 
						|
   */
 | 
						|
  static class Input
 | 
						|
    implements Location
 | 
						|
  {
 | 
						|
 | 
						|
    int line = 1, markLine;
 | 
						|
    int column, markColumn;
 | 
						|
    int offset, markOffset;
 | 
						|
    final String publicId, systemId, name;
 | 
						|
    final boolean report; // report start- and end-entity
 | 
						|
    final boolean normalize; // normalize CR, etc to LF
 | 
						|
 | 
						|
    InputStream in;
 | 
						|
    Reader reader;
 | 
						|
    UnicodeReader unicodeReader;
 | 
						|
    boolean initialized;
 | 
						|
    boolean encodingDetected;
 | 
						|
    String inputEncoding;
 | 
						|
    boolean xml11;
 | 
						|
 | 
						|
    Input(InputStream in, Reader reader, String publicId, String systemId,
 | 
						|
          String name, String inputEncoding, boolean report,
 | 
						|
          boolean normalize)
 | 
						|
    {
 | 
						|
      if (inputEncoding == null)
 | 
						|
        inputEncoding = "UTF-8";
 | 
						|
      this.inputEncoding = inputEncoding;
 | 
						|
      this.publicId = publicId;
 | 
						|
      this.systemId = systemId;
 | 
						|
      this.name = name;
 | 
						|
      this.report = report;
 | 
						|
      this.normalize = normalize;
 | 
						|
      if (in != null)
 | 
						|
        {
 | 
						|
          if (reader != null)
 | 
						|
            throw new IllegalStateException("both byte and char streams "+
 | 
						|
                                            "specified");
 | 
						|
          if (normalize)
 | 
						|
            in = new CRLFInputStream(in);
 | 
						|
          in = new BufferedInputStream(in);
 | 
						|
          this.in = in;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          this.reader = normalize ? new CRLFReader(reader) : reader;
 | 
						|
          unicodeReader = new UnicodeReader(this.reader);
 | 
						|
        }
 | 
						|
      initialized = false;
 | 
						|
    }
 | 
						|
 | 
						|
    // -- Location --
 | 
						|
 | 
						|
    public int getCharacterOffset()
 | 
						|
    {
 | 
						|
      return offset;
 | 
						|
    }
 | 
						|
 | 
						|
    public int getColumnNumber()
 | 
						|
    {
 | 
						|
      return column;
 | 
						|
    }
 | 
						|
 | 
						|
    public int getLineNumber()
 | 
						|
    {
 | 
						|
      return line;
 | 
						|
    }
 | 
						|
 | 
						|
    public String getPublicId()
 | 
						|
    {
 | 
						|
      return publicId;
 | 
						|
    }
 | 
						|
 | 
						|
    public String getSystemId()
 | 
						|
    {
 | 
						|
      return systemId;
 | 
						|
    }
 | 
						|
 | 
						|
    void init()
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      if (initialized)
 | 
						|
        return;
 | 
						|
      if (in != null)
 | 
						|
        detectEncoding();
 | 
						|
      initialized = true;
 | 
						|
    }
 | 
						|
 | 
						|
    void mark(int len)
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      markOffset = offset;
 | 
						|
      markLine = line;
 | 
						|
      markColumn = column;
 | 
						|
      if (unicodeReader != null)
 | 
						|
        unicodeReader.mark(len);
 | 
						|
      else
 | 
						|
        in.mark(len);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Character read.
 | 
						|
     */
 | 
						|
    int read()
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      offset++;
 | 
						|
      int ret = (unicodeReader != null) ? unicodeReader.read() : in.read();
 | 
						|
      if (normalize &&
 | 
						|
          (ret == 0x0d || (xml11 && (ret == 0x85 || ret == 0x2028))))
 | 
						|
        {
 | 
						|
          // Normalize CR etc to LF
 | 
						|
          ret = 0x0a;
 | 
						|
        }
 | 
						|
      // Locator handling
 | 
						|
      if (ret == 0x0a)
 | 
						|
        {
 | 
						|
          line++;
 | 
						|
          column = 0;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        column++;
 | 
						|
      return ret;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Block read.
 | 
						|
     */
 | 
						|
    int read(int[] b, int off, int len)
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      int ret;
 | 
						|
      if (unicodeReader != null)
 | 
						|
        {
 | 
						|
          ret = unicodeReader.read(b, off, len);
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          byte[] b2 = new byte[len];
 | 
						|
          ret = in.read(b2, 0, len);
 | 
						|
          if (ret != -1)
 | 
						|
            {
 | 
						|
              String s = new String(b2, 0, ret, inputEncoding);
 | 
						|
              int[] c = UnicodeReader.toCodePointArray(s);
 | 
						|
              ret = c.length;
 | 
						|
              System.arraycopy(c, 0, b, off, ret);
 | 
						|
            }
 | 
						|
        }
 | 
						|
      if (ret != -1)
 | 
						|
        {
 | 
						|
          // Locator handling
 | 
						|
          for (int i = 0; i < ret; i++)
 | 
						|
            {
 | 
						|
              int c = b[off + i];
 | 
						|
              if (normalize &&
 | 
						|
                  (c == 0x0d || (xml11 && (c == 0x85 || c == 0x2028))))
 | 
						|
                {
 | 
						|
                  // Normalize CR etc to LF
 | 
						|
                  c = 0x0a;
 | 
						|
                  b[off + i] = c;
 | 
						|
                }
 | 
						|
              if (c == 0x0a)
 | 
						|
                {
 | 
						|
                  line++;
 | 
						|
                  column = 0;
 | 
						|
                }
 | 
						|
              else
 | 
						|
                column++;
 | 
						|
            }
 | 
						|
        }
 | 
						|
      return ret;
 | 
						|
    }
 | 
						|
 | 
						|
    void reset()
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      if (unicodeReader != null)
 | 
						|
        unicodeReader.reset();
 | 
						|
      else
 | 
						|
        in.reset();
 | 
						|
      offset = markOffset;
 | 
						|
      line = markLine;
 | 
						|
      column = markColumn;
 | 
						|
    }
 | 
						|
 | 
						|
    // Detection of input encoding
 | 
						|
 | 
						|
    private static final int[] SIGNATURE_UCS_4_1234 =
 | 
						|
      new int[] { 0x00, 0x00, 0x00, 0x3c };
 | 
						|
    private static final int[] SIGNATURE_UCS_4_4321 =
 | 
						|
      new int[] { 0x3c, 0x00, 0x00, 0x00 };
 | 
						|
    private static final int[] SIGNATURE_UCS_4_2143 =
 | 
						|
      new int[] { 0x00, 0x00, 0x3c, 0x00 };
 | 
						|
    private static final int[] SIGNATURE_UCS_4_3412 =
 | 
						|
      new int[] { 0x00, 0x3c, 0x00, 0x00 };
 | 
						|
    private static final int[] SIGNATURE_UCS_2_12 =
 | 
						|
      new int[] { 0xfe, 0xff };
 | 
						|
    private static final int[] SIGNATURE_UCS_2_21 =
 | 
						|
      new int[] { 0xff, 0xfe };
 | 
						|
    private static final int[] SIGNATURE_UCS_2_12_NOBOM =
 | 
						|
      new int[] { 0x00, 0x3c, 0x00, 0x3f };
 | 
						|
    private static final int[] SIGNATURE_UCS_2_21_NOBOM =
 | 
						|
      new int[] { 0x3c, 0x00, 0x3f, 0x00 };
 | 
						|
    private static final int[] SIGNATURE_UTF_8 =
 | 
						|
      new int[] { 0x3c, 0x3f, 0x78, 0x6d };
 | 
						|
    private static final int[] SIGNATURE_UTF_8_BOM =
 | 
						|
      new int[] { 0xef, 0xbb, 0xbf };
 | 
						|
 | 
						|
    /**
 | 
						|
     * Detect the input encoding.
 | 
						|
     */
 | 
						|
    private void detectEncoding()
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      int[] signature = new int[4];
 | 
						|
      in.mark(4);
 | 
						|
      for (int i = 0; i < 4; i++)
 | 
						|
        signature[i] = in.read();
 | 
						|
      in.reset();
 | 
						|
 | 
						|
      // 4-byte encodings
 | 
						|
      if (equals(SIGNATURE_UCS_4_1234, signature))
 | 
						|
        {
 | 
						|
          in.read();
 | 
						|
          in.read();
 | 
						|
          in.read();
 | 
						|
          in.read();
 | 
						|
          setInputEncoding("UTF-32BE");
 | 
						|
          encodingDetected = true;
 | 
						|
        }
 | 
						|
      else if (equals(SIGNATURE_UCS_4_4321, signature))
 | 
						|
        {
 | 
						|
          in.read();
 | 
						|
          in.read();
 | 
						|
          in.read();
 | 
						|
          in.read();
 | 
						|
          setInputEncoding("UTF-32LE");
 | 
						|
          encodingDetected = true;
 | 
						|
        }
 | 
						|
      else if (equals(SIGNATURE_UCS_4_2143, signature) ||
 | 
						|
               equals(SIGNATURE_UCS_4_3412, signature))
 | 
						|
        throw new UnsupportedEncodingException("unsupported UCS-4 byte ordering");
 | 
						|
 | 
						|
      // 2-byte encodings
 | 
						|
      else if (equals(SIGNATURE_UCS_2_12, signature))
 | 
						|
        {
 | 
						|
          in.read();
 | 
						|
          in.read();
 | 
						|
          setInputEncoding("UTF-16BE");
 | 
						|
          encodingDetected = true;
 | 
						|
        }
 | 
						|
      else if (equals(SIGNATURE_UCS_2_21, signature))
 | 
						|
        {
 | 
						|
          in.read();
 | 
						|
          in.read();
 | 
						|
          setInputEncoding("UTF-16LE");
 | 
						|
          encodingDetected = true;
 | 
						|
        }
 | 
						|
      else if (equals(SIGNATURE_UCS_2_12_NOBOM, signature))
 | 
						|
        {
 | 
						|
          //setInputEncoding("UTF-16BE");
 | 
						|
          throw new UnsupportedEncodingException("no byte-order mark for UCS-2 entity");
 | 
						|
        }
 | 
						|
      else if (equals(SIGNATURE_UCS_2_21_NOBOM, signature))
 | 
						|
        {
 | 
						|
          //setInputEncoding("UTF-16LE");
 | 
						|
          throw new UnsupportedEncodingException("no byte-order mark for UCS-2 entity");
 | 
						|
        }
 | 
						|
      // ASCII-derived encodings
 | 
						|
      else if (equals(SIGNATURE_UTF_8, signature))
 | 
						|
        {
 | 
						|
          // UTF-8 input encoding implied, TextDecl
 | 
						|
        }
 | 
						|
      else if (equals(SIGNATURE_UTF_8_BOM, signature))
 | 
						|
        {
 | 
						|
          in.read();
 | 
						|
          in.read();
 | 
						|
          in.read();
 | 
						|
          setInputEncoding("UTF-8");
 | 
						|
          encodingDetected = true;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private static boolean equals(int[] b1, int[] b2)
 | 
						|
    {
 | 
						|
      for (int i = 0; i < b1.length; i++)
 | 
						|
        {
 | 
						|
          if (b1[i] != b2[i])
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    void setInputEncoding(String encoding)
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      if (encoding.equals(inputEncoding))
 | 
						|
        return;
 | 
						|
      if ("UTF-16".equalsIgnoreCase(encoding) &&
 | 
						|
          inputEncoding.startsWith("UTF-16"))
 | 
						|
        return;
 | 
						|
      if (encodingDetected)
 | 
						|
        throw new UnsupportedEncodingException("document is not in its " +
 | 
						|
                                               "declared encoding " +
 | 
						|
                                               inputEncoding +
 | 
						|
                                               ": " + encoding);
 | 
						|
      inputEncoding = encoding;
 | 
						|
      finalizeEncoding();
 | 
						|
    }
 | 
						|
 | 
						|
    void finalizeEncoding()
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      if (reader != null)
 | 
						|
        return;
 | 
						|
      reader = new BufferedReader(new InputStreamReader(in, inputEncoding));
 | 
						|
      unicodeReader = new UnicodeReader(reader);
 | 
						|
      mark(1);
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
}
 |