gt:         return findEntity(id, null);
context: /* Woodstox XML processor
   *
   * Copyright (c) 2004- Tatu Saloranta, tatu.saloranta@iki.fi
   *
   * Licensed under the License specified in file LICENSE, included with
   * the source code.
   * You may not use this file except in compliance with the License.
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.ctc.wstx.sr;
  
  import java.io.FileNotFoundException;
  import java.io.IOException;
  import java.net.URL;
  import java.text.MessageFormat;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Map;
  
  import javax.xml.stream.Location;
  import javax.xml.stream.XMLInputFactory;
  import javax.xml.stream.XMLReporter;
  import javax.xml.stream.XMLResolver;
  import javax.xml.stream.XMLStreamException;
  
  import org.codehaus.stax2.XMLReporter2;
  import org.codehaus.stax2.XMLStreamLocation2;
  import org.codehaus.stax2.validation.XMLValidationProblem;
  
  import com.ctc.wstx.api.ReaderConfig;
  import com.ctc.wstx.cfg.ErrorConsts;
  import com.ctc.wstx.cfg.InputConfigFlags;
  import com.ctc.wstx.cfg.ParsingErrorMsgs;
  import com.ctc.wstx.cfg.XmlConsts;
  import com.ctc.wstx.dtd.MinimalDTDReader;
  import com.ctc.wstx.ent.EntityDecl;
  import com.ctc.wstx.ent.IntEntity;
  import com.ctc.wstx.exc.*;
  import com.ctc.wstx.io.DefaultInputResolver;
  import com.ctc.wstx.io.WstxInputData;
  import com.ctc.wstx.io.WstxInputLocation;
  import com.ctc.wstx.io.WstxInputSource;
  import com.ctc.wstx.util.ExceptionUtil;
  import com.ctc.wstx.util.SymbolTable;
  import com.ctc.wstx.util.TextBuffer;
  
  /**
   * Abstract base class that defines some basic functionality that all
   * Woodstox reader classes (main XML reader, DTD reader) extend from.
   */
  
  public abstract class StreamScanner
      extends WstxInputData
      implements InputProblemReporter,
          InputConfigFlags, ParsingErrorMsgs
  {
  
      // // // Some well-known chars:
  
      /**
       * Last (highest) char code of the three, LF, CR and NULL
       */
      public final static char CHAR_CR_LF_OR_NULL = (char) 13;
  
      public final static int INT_CR_LF_OR_NULL = 13;
  
      /**
       * Character that allows quick check of whether a char can potentially
       * be some kind of markup, WRT input stream processing;
       * has to contain linefeeds, &, < and > (">" only matters when
       * quoting text, as part of "]]>")
       */
      protected final static char CHAR_FIRST_PURE_TEXT = (char) ('>' + 1);
  
  
      /**
       * First character in Unicode (ie one with lowest id) that is legal
       * as part of a local name (all valid name chars minus ':'). Used
       * for doing quick check for local name end; usually name ends in
       * a whitespace or equals sign.
       */
      protected final static char CHAR_LOWEST_LEGAL_LOCALNAME_CHAR = '-';
  
      /*
      ///////////////////////////////////////////////////////////
      // Character validity constants, structs
      ///////////////////////////////////////////////////////////
       */
  
      /**
       * We will only use validity array for first 256 characters, mostly
       * because after those characters it's easier to do fairly simple
       * block checks.
       */
      private final static int VALID_CHAR_COUNT = 0x100;
  
      private final static byte NAME_CHAR_INVALID_B = (byte) 0;
      private final static byte NAME_CHAR_ALL_VALID_B = (byte) 1;
      private final static byte NAME_CHAR_VALID_NONFIRST_B = (byte) -1;
  
      private final static byte[] sCharValidity = new byte[VALID_CHAR_COUNT];
  
      static {
          /* First, since all valid-as-first chars are also valid-as-other chars,
           * we'll initialize common chars:
           */
          sCharValidity['_'] = NAME_CHAR_ALL_VALID_B;
          for (int i = 0, last = ('z' - 'a'); i <= last; ++i) {
              sCharValidity['A' + i] = NAME_CHAR_ALL_VALID_B;
              sCharValidity['a' + i] = NAME_CHAR_ALL_VALID_B;
          }
          for (int i = 0xC0; i < 0xF6; ++i) { // not all are fully valid, but
              sCharValidity[i] = NAME_CHAR_ALL_VALID_B;
          }
          // ... now we can 'revert' ones not fully valid:
          sCharValidity[0xD7] = NAME_CHAR_INVALID_B;
          sCharValidity[0xF7] = NAME_CHAR_INVALID_B;
  
          /* And then we can proceed with ones only valid-as-other.
           */
          sCharValidity['-'] = NAME_CHAR_VALID_NONFIRST_B;
          sCharValidity['.'] = NAME_CHAR_VALID_NONFIRST_B;
          sCharValidity[0xB7] = NAME_CHAR_VALID_NONFIRST_B;
          for (int i = '0'; i <= '9'; ++i) {
              sCharValidity[i] = NAME_CHAR_VALID_NONFIRST_B;
          }
      }
  
      /**
       * Public identifiers only use 7-bit ascii range.
       */
      private final static int VALID_PUBID_CHAR_COUNT = 0x80;
      private final static byte[] sPubidValidity = new byte[VALID_PUBID_CHAR_COUNT];
  //    private final static byte PUBID_CHAR_INVALID_B = (byte) 0;
      private final static byte PUBID_CHAR_VALID_B = (byte) 1;
      static {
          for (int i = 0, last = ('z' - 'a'); i <= last; ++i) {
              sPubidValidity['A' + i] = PUBID_CHAR_VALID_B;
              sPubidValidity['a' + i] = PUBID_CHAR_VALID_B;
          }
          for (int i = '0'; i <= '9'; ++i) {
              sPubidValidity[i] = PUBID_CHAR_VALID_B;
          }
  
          // 3 main white space types are valid
          sPubidValidity[0x0A] = PUBID_CHAR_VALID_B;
          sPubidValidity[0x0D] = PUBID_CHAR_VALID_B;
          sPubidValidity[0x20] = PUBID_CHAR_VALID_B;
  
          // And many of punctuation/separator ascii chars too:
          sPubidValidity['-'] = PUBID_CHAR_VALID_B;
          sPubidValidity['\''] = PUBID_CHAR_VALID_B;
          sPubidValidity['('] = PUBID_CHAR_VALID_B;
          sPubidValidity[')'] = PUBID_CHAR_VALID_B;
          sPubidValidity['+'] = PUBID_CHAR_VALID_B;
          sPubidValidity[','] = PUBID_CHAR_VALID_B;
          sPubidValidity['.'] = PUBID_CHAR_VALID_B;
          sPubidValidity['/'] = PUBID_CHAR_VALID_B;
          sPubidValidity[':'] = PUBID_CHAR_VALID_B;
          sPubidValidity['='] = PUBID_CHAR_VALID_B;
          sPubidValidity['?'] = PUBID_CHAR_VALID_B;
          sPubidValidity[';'] = PUBID_CHAR_VALID_B;
          sPubidValidity['!'] = PUBID_CHAR_VALID_B;
          sPubidValidity['*'] = PUBID_CHAR_VALID_B;
          sPubidValidity['#'] = PUBID_CHAR_VALID_B;
          sPubidValidity['@'] = PUBID_CHAR_VALID_B;
          sPubidValidity['$'] = PUBID_CHAR_VALID_B;
          sPubidValidity['_'] = PUBID_CHAR_VALID_B;
          sPubidValidity['%'] = PUBID_CHAR_VALID_B;
      }
  
      /*
      ///////////////////////////////////////////////////////////
      // Basic configuration
      ///////////////////////////////////////////////////////////
       */
  
      /**
       * Copy of the configuration object passed by the factory.
       * Contains immutable settings for this reader (or in case
       * of DTD parsers, reader that uses it)
       */
      protected final ReaderConfig mConfig;
  
      // // // Various extracted settings:
  
      /**
       * If true, Reader is namespace aware, and should do basic checks
       * (usually enforcing limitations on having colons in names)
       */
      protected final boolean mCfgNsEnabled;
  
      // Extracted standard on/off settings:
  
      /**
       * note: left non-final on purpose: sub-class may need to modify
       * the default value after construction.
       */
      protected boolean mCfgReplaceEntities;
  
      /*
      ///////////////////////////////////////////////////////////
      // Symbol handling, if applicable
      ///////////////////////////////////////////////////////////
       */
  
      final SymbolTable mSymbols;
  
      /**
       * Local full name for the event, if it has one (note: element events
       * do NOT use this variable; those names are stored in element stack):
       * target for processing instructions.
       *<p>
       * Currently used for proc. instr. target, and entity name (at least
       * when current entity reference is null).
       *<p>
       * Note: this variable is generally not cleared, since it comes from
       * a symbol table, ie. this won't be the only reference.
       */
      protected String mCurrName;
  
      /*
      ///////////////////////////////////////////////////////////
      // Input handling
      ///////////////////////////////////////////////////////////
       */
  
      /**
       * Currently active input source; contains link to parent (nesting) input
       * sources, if any.
       */
      protected WstxInputSource mInput;
  
      /**
       * Top-most input source this reader can use; due to input source
       * chaining, this is not necessarily the root of all input; for example,
       * external DTD subset reader's root input still has original document
       * input as its parent.
       */
      protected final WstxInputSource mRootInput;
  
      /**
       * Custom resolver used to handle external entities that are to be expanded
       * by this reader (external param/general entity expander)
       */
      XMLResolver mEntityResolver = null;
  
      /**
       * This is the current depth of the input stack (same as what input
       * element stack would return as its depth).
       * It is used to enforce input scope constraints for nesting of
       * elements (for xml reader) and dtd declaration (for dtd reader)
       * with regards to input block (entity expansion) boundaries.
       *<p>
       * Basically this value is compared to {@link #mInputTopDepth}, which
       * indicates what was the depth at the point where the currently active
       * input scope/block was started.
       */
      protected int mCurrDepth = 0;
  
      protected int mInputTopDepth = 0;
  
      /**
       * Flag that indicates whether linefeeds in the input data are to
       * be normalized or not.
       * Xml specs mandate that the line feeds are only normalized
       * when they are from the external entities (main doc, external
       * general/parsed entities), so normalization has to be
       * suppressed when expanding internal general/parsed entities.
       */
      protected boolean mNormalizeLFs;
  
      /**
       * Flag that indicates whether all escaped chars are accepted in XML 1.0.
       */
      protected boolean mXml10AllowAllEscapedChars = true;
  
  
      /*
      ///////////////////////////////////////////////////////////
      // Buffer(s) for local name(s) and text content
      ///////////////////////////////////////////////////////////
       */
  
      /**
       * Temporary buffer used if local name can not be just directly
       * constructed from input buffer (name is on a boundary or such).
       */
      protected char[] mNameBuffer = null;
  
      /*
      ///////////////////////////////////////////////////////////
      // Information about starting location of event
      // Reader is pointing to; updated on-demand
      ///////////////////////////////////////////////////////////
       */
  
      // // // Location info at point when current token was started
  
      /**
       * Total number of characters read before start of current token.
       * For big (gigabyte-sized) sizes are possible, needs to be long,
       * unlike pointers and sizes related to in-memory buffers.
       */
      protected long mTokenInputTotal = 0; 
  
      /**
       * Input row on which current token starts, 1-based
       */
      protected int mTokenInputRow = 1;
  
      /**
       * Column on input row that current token starts; 0-based (although
       * in the end it'll be converted to 1-based)
       */
      protected int mTokenInputCol = 0;
  
      /*
      ///////////////////////////////////////////////////////////
      // XML document information (from doc decl if one
      // was found) common to all entities (main xml
      // document, external DTD subset)
      ///////////////////////////////////////////////////////////
       */
  
      /**
       * Input stream encoding, if known (passed in, or determined by
       * auto-detection); null if not.
       */
      String mDocInputEncoding = null;
  
      /**
       * Character encoding from xml declaration, if any; null if no
       * declaration, or it didn't specify encoding.
       */
      String mDocXmlEncoding = null;
  
      /**
       * XML version as declared by the document; one of constants
       * from {@link XmlConsts} (like {@link XmlConsts#XML_V_10}).
       */
      protected int mDocXmlVersion = XmlConsts.XML_V_UNKNOWN;
      
      /**
       * Cache of internal character entities;
       */
      protected Map mCachedEntities;
      
      /**
       * Flag for whether or not character references should be treated as entities
       */
      protected boolean mCfgTreatCharRefsAsEntities;
      
      /**
       * Entity reference stream currently points to.
       */
      protected EntityDecl mCurrEntity;
  
      /*
      ///////////////////////////////////////////////////////////
      // Life-cycle
      ///////////////////////////////////////////////////////////
       */
  
      /**
       * Constructor used when creating a complete new (main-level) reader that
       * does not share its input buffers or state with another reader.
       */
      protected StreamScanner(WstxInputSource input, ReaderConfig cfg,
                              XMLResolver res)
      {
          super();
          mInput = input;
          // 17-Jun-2004, TSa: Need to know root-level input source
          mRootInput = input;
  
          mConfig = cfg;
          mSymbols = cfg.getSymbols();
          int cf = cfg.getConfigFlags();
          mCfgNsEnabled = (cf & CFG_NAMESPACE_AWARE) != 0;
          mCfgReplaceEntities = (cf & CFG_REPLACE_ENTITY_REFS) != 0;
  
          mNormalizeLFs = mConfig.willNormalizeLFs();
          mInputBuffer = null;
          mInputPtr = mInputEnd = 0;
          mEntityResolver = res;
          
          mCfgTreatCharRefsAsEntities = mConfig.willTreatCharRefsAsEnts();
          mCachedEntities = mCfgTreatCharRefsAsEntities ? new HashMap() : Collections.EMPTY_MAP;
      }
  
      /*
      ///////////////////////////////////////////////////////////
      // Package API
      ///////////////////////////////////////////////////////////
       */
  
      /**
       * Method that returns location of the last character returned by this
       * reader; that is, location "one less" than the currently pointed to
       * location.
       */
      protected WstxInputLocation getLastCharLocation()
      {
          return mInput.getLocation(mCurrInputProcessed + mInputPtr - 1,
                                    mCurrInputRow,
                                    mInputPtr - mCurrInputRowStart);
      }
  
      protected URL getSource() {
          return mInput.getSource();
      }
  
      protected String getSystemId() {
          return mInput.getSystemId();
      }
  
      /*
      ///////////////////////////////////////////////////////////
      // Partial LocationInfo implementation (not implemented
      // by this base class, but is by some sub-classes)
      ///////////////////////////////////////////////////////////
       */
  
      /**
       * Returns location of last properly parsed token; as per StAX specs,
       * apparently needs to be the end of current event, which is the same
       * as the start of the following event (or EOF if that's next).
       */
      public abstract Location getLocation();
  
      public XMLStreamLocation2 getStartLocation()
      {
          // note: +1 is used as columns are 1-based...
          return mInput.getLocation(mTokenInputTotal, mTokenInputRow,
                                    mTokenInputCol + 1);
      }
  
      public XMLStreamLocation2 getCurrentLocation()
      {
          return mInput.getLocation(mCurrInputProcessed + mInputPtr,
                                    mCurrInputRow,
                                    mInputPtr - mCurrInputRowStart + 1);
      }
  
      /*
      ///////////////////////////////////////////////////////////
      // InputProblemReporter implementation
      ///////////////////////////////////////////////////////////
       */
  
      public WstxException throwWfcException(String msg, boolean deferErrors)
          throws WstxException
      {
          WstxException ex = constructWfcException(msg);
          if (!deferErrors) {
              throw ex;
          }
          return ex;
      }
  
      public void throwParseError(String msg) throws XMLStreamException
      {
          throwParseError(msg, null, null);
      }
  
      /**
       * Throws generic parse error with specified message and current parsing
       * location.
       *<p>
       * Note: public access only because core code in other packages needs
       * to access it.
       */
      public void throwParseError(String format, Object arg, Object arg2)
          throws XMLStreamException
      {
          String msg = (arg != null || arg2 != null) ?
              MessageFormat.format(format, new Object[] { arg, arg2 }) : format;
          throw constructWfcException(msg);
      }
  
      public void reportProblem(String probType, String format, Object arg, Object arg2)
          throws XMLStreamException
      {
          XMLReporter rep = mConfig.getXMLReporter();
          if (rep != null) {
              _reportProblem(rep, probType,
                              MessageFormat.format(format, new Object[] { arg, arg2 }), null);
          }
      }
  
      public void reportProblem(Location loc, String probType,
                                String format, Object arg, Object arg2)
          throws XMLStreamException
      {
          XMLReporter rep = mConfig.getXMLReporter();
          if (rep != null) {
              String msg = (arg != null || arg2 != null) ?
                  MessageFormat.format(format, new Object[] { arg, arg2 }) : format;
              _reportProblem(rep, probType, msg, loc);
          }
      }
  
      protected void _reportProblem(XMLReporter rep, String probType, String msg, Location loc)
          throws XMLStreamException
      {
          if (loc == null) {
              loc = getLastCharLocation();
          }
          _reportProblem(rep, new XMLValidationProblem(loc, msg, XMLValidationProblem.SEVERITY_ERROR, probType));
      }
  
      protected void _reportProblem(XMLReporter rep, XMLValidationProblem prob)
          throws XMLStreamException
      {
          if (rep != null) {
              Location loc = prob.getLocation();
              if (loc == null) {
                  loc = getLastCharLocation();
                  prob.setLocation(loc);
              }
              // Backwards-compatibility fix: add non-null type, if missing:
              if (prob.getType() == null) {
                  prob.setType(ErrorConsts.WT_VALIDATION);
              }
              // [WSTX-154]: was catching and dropping thrown exception: shouldn't.
              // [WTSX-157]: need to support XMLReporter2
              if (rep instanceof XMLReporter2) {
                  ((XMLReporter2) rep).report(prob);
              } else {
                  rep.report(prob.getMessage(), prob.getType(), prob, loc);
              }
          }
      }
  
      /**
       *<p>
       * Note: this is the base implementation used for implementing
       * <code>ValidationContext</code>
       */
      public void reportValidationProblem(XMLValidationProblem prob)
          throws XMLStreamException
      {
          // !!! TBI: Fail-fast vs. deferred modes?
          /* For now let's implement basic functionality: warnings get
           * reported via XMLReporter, errors and fatal errors result in
           * immediate exceptions.
           */
          /* 27-May-2008, TSa: [WSTX-153] Above is incorrect: as per Stax
           *   javadocs for XMLReporter, both warnings and non-fatal errors
           *   (which includes all validation errors) should be reported via
           *   XMLReporter interface, and only fatals should cause an
           *   immediate stream exception (by-passing reporter)
           */
          if (prob.getSeverity() > XMLValidationProblem.SEVERITY_ERROR) {
              throw WstxValidationException.create(prob);
          }
          XMLReporter rep = mConfig.getXMLReporter();
          if (rep != null) {
              _reportProblem(rep, prob);
          } else {
              /* If no reporter, regular non-fatal errors are to be reported
               * as exceptions as well, for backwards compatibility
               */
              if (prob.getSeverity() >= XMLValidationProblem.SEVERITY_ERROR) {
                  throw WstxValidationException.create(prob);
              }
          }
      }
  
      public void reportValidationProblem(String msg, int severity)
          throws XMLStreamException
      {
          reportValidationProblem(new XMLValidationProblem(getLastCharLocation(),
                                                           msg, severity));
      }
  
      public void reportValidationProblem(String msg)
          throws XMLStreamException
      {
          reportValidationProblem(new XMLValidationProblem(getLastCharLocation(),
                                                           msg,
                                                           XMLValidationProblem.SEVERITY_ERROR));
      }
  
      public void reportValidationProblem(Location loc, String msg)
          throws XMLStreamException
      {
          reportValidationProblem(new XMLValidationProblem(loc, msg));
      }
  
      public void reportValidationProblem(String format, Object arg, Object arg2)
          throws XMLStreamException
      {
          reportValidationProblem(MessageFormat.format(format, new Object[] { arg, arg2 }));
      }
  
      /*
      ///////////////////////////////////////////////////////////
      // Other error reporting methods
      ///////////////////////////////////////////////////////////
       */
  
      protected WstxException constructWfcException(String msg)
      {
          return new WstxParsingException(msg, getLastCharLocation());
      }
  
      /**
       * Construct and return a {@link XMLStreamException} to throw
       * as a result of a failed Typed Access operation (but one not
       * caused by a Well-Formedness Constraint or Validation Constraint
       * problem)
       */
      /*
      protected WstxException _constructTypeException(String msg)
      {
          // Hmmh. Should there be a distinct sub-type?
          return new WstxParsingException(msg, getLastCharLocation());
      }
      */
  
      protected WstxException constructFromIOE(IOException ioe)
      {
          return new WstxIOException(ioe);
      }
  
      protected WstxException constructNullCharException()
      {
          return new WstxUnexpectedCharException("Illegal character (NULL, unicode 0) encountered: not valid in any content",
                  getLastCharLocation(), CHAR_NULL);
      }
  
      protected void throwUnexpectedChar(int i, String msg)
          throws WstxException
      {
          char c = (char) i;
          String excMsg = "Unexpected character "+getCharDesc(c)+msg;
          throw new WstxUnexpectedCharException(excMsg, getLastCharLocation(), c);
      }
  
      protected void throwNullChar()
          throws WstxException
      {
          throw constructNullCharException();
      }
  
      protected void throwInvalidSpace(int i)
          throws WstxException
      {
          throwInvalidSpace(i, false);
      }
  
      protected WstxException throwInvalidSpace(int i, boolean deferErrors)
          throws WstxException
      {
          char c = (char) i;
          WstxException ex;
          if (c == CHAR_NULL) {
              ex = constructNullCharException();
          } else {
              String msg = "Illegal character ("+getCharDesc(c)+")";
              if (mXml11) {
                  msg += " [note: in XML 1.1, it could be included via entity expansion]";
              }
              ex = new WstxUnexpectedCharException(msg, getLastCharLocation(), c);
          }
          if (!deferErrors) {
              throw ex;
          }
          return ex;
      }
  
      protected void throwUnexpectedEOF(String msg)
          throws WstxException
      {
          throw new WstxEOFException("Unexpected EOF"
                                     +(msg == null ? "" : msg),
                                     getLastCharLocation());
      }
  
      /**
       * Similar to {@link #throwUnexpectedEOF}, but only indicates ending
       * of an input block. Used when reading a token that can not span
       * input block boundaries (ie. can not continue past end of an
       * entity expansion).
       */
      protected void throwUnexpectedEOB(String msg)
          throws WstxException
      {
          throw new WstxEOFException("Unexpected end of input block"
                                     +(msg == null ? "" : msg),
                                     getLastCharLocation());
      }
  
      protected void throwFromIOE(IOException ioe)
          throws WstxException
      {
          throw new WstxIOException(ioe);
      }
  
      protected void throwFromStrE(XMLStreamException strex)
          throws WstxException
      {
          if (strex instanceof WstxException) {
              throw (WstxException) strex;
          }
          WstxException newEx = new WstxException(strex);
          ExceptionUtil.setInitCause(newEx, strex);
          throw newEx;
      }
  
      /**
       * Method called to report an error, when caller's signature only
       * allows runtime exceptions to be thrown.
       */
      protected void throwLazyError(Exception e)
      {
          if (e instanceof XMLStreamException) {
              WstxLazyException.throwLazily((XMLStreamException) e);
          }
          ExceptionUtil.throwRuntimeException(e);
      }
  
      protected String tokenTypeDesc(int type)
      {
          return ErrorConsts.tokenTypeDesc(type);
      }
  
      /*
      ///////////////////////////////////////////////////////////
      // Input buffer handling
      ///////////////////////////////////////////////////////////
       */
  
      /**
       * Returns current input source this source uses.
       *<p>
       * Note: public only because some implementations are on different
       * package.
       */
      public final WstxInputSource getCurrentInput() {
          return mInput;
      }
  
      protected final int inputInBuffer() {
          return mInputEnd - mInputPtr;
      }
  
      protected final int getNext()
          throws XMLStreamException
      {
          if (mInputPtr >= mInputEnd) {
              if (!loadMore()) {
                  return -1;
              }
          }
          return (int) mInputBuffer[mInputPtr++];
      }
  
      /**
       * Similar to {@link #getNext}, but does not advance pointer
       * in input buffer.
       *<p>
       * Note: this method only peeks within current input source;
       * it does not close it and check nested input source (if any).
       * This is necessary when checking keywords, since they can never
       * cross input block boundary.
       */
      protected final int peekNext()
          throws XMLStreamException
      {
          if (mInputPtr >= mInputEnd) {
              if (!loadMoreFromCurrent()) {
                  return -1;
              }
          }
          return (int) mInputBuffer[mInputPtr];
      }
  
      protected final char getNextChar(String errorMsg)
          throws XMLStreamException
      {
          if (mInputPtr >= mInputEnd) {
              loadMore(errorMsg);
          }
          return mInputBuffer[mInputPtr++];
      }
  
      /**
       * Similar to {@link #getNextChar}, but will not read more characters
       * from parent input source(s) if the current input source doesn't
       * have more content. This is often needed to prevent "runaway" content,
       * such as comments that start in an entity but do not have matching
       * close marker inside entity; XML specification specifically states
       * such markup is not legal.
       */
      protected final char getNextCharFromCurrent(String errorMsg)
          throws XMLStreamException
      {
          if (mInputPtr >= mInputEnd) {
              loadMoreFromCurrent(errorMsg);
          }
          return mInputBuffer[mInputPtr++];
      }
  
      /**
       * Method that will skip through zero or more white space characters,
       * and return either the character following white space, or -1 to
       * indicate EOF (end of the outermost input source)/
       */
      protected final int getNextAfterWS()
          throws XMLStreamException
      {
          if (mInputPtr >= mInputEnd) {
              if (!loadMore()) {
                  return -1;
              }
          }
          char c = mInputBuffer[mInputPtr++];
          while (c <= CHAR_SPACE) {
              // Linefeed?
              if (c == '\n' || c == '\r') {
                  skipCRLF(c);
              } else if (c != CHAR_SPACE && c != '\t') {
                  throwInvalidSpace(c);
              }
              // Still a white space?
              if (mInputPtr >= mInputEnd) {
                  if (!loadMore()) {
                      return -1;
                  }
              }
              c = mInputBuffer[mInputPtr++];
          }
          return (int) c;
      }
  
      protected final char getNextCharAfterWS(String errorMsg)
          throws XMLStreamException
      {
          if (mInputPtr >= mInputEnd) {
              loadMore(errorMsg);
          }
  
          char c = mInputBuffer[mInputPtr++];
          while (c <= CHAR_SPACE) {
              // Linefeed?
              if (c == '\n' || c == '\r') {
                  skipCRLF(c);
              } else if (c != CHAR_SPACE && c != '\t') {
                  throwInvalidSpace(c);
              }
  
              // Still a white space?
              if (mInputPtr >= mInputEnd) {
                  loadMore(errorMsg);
              }
              c = mInputBuffer[mInputPtr++];
          }
          return c;
      }
  
      protected final char getNextInCurrAfterWS(String errorMsg)
          throws XMLStreamException
      {
          return getNextInCurrAfterWS(errorMsg, getNextCharFromCurrent(errorMsg));
      }
  
      protected final char getNextInCurrAfterWS(String errorMsg, char c)
          throws XMLStreamException
      {
          while (c <= CHAR_SPACE) {
              // Linefeed?
              if (c == '\n' || c == '\r') {
                  skipCRLF(c);
              } else if (c != CHAR_SPACE && c != '\t') {
                  throwInvalidSpace(c);
              }
  
              // Still a white space?
              if (mInputPtr >= mInputEnd) {
                  loadMoreFromCurrent(errorMsg);
              }
              c = mInputBuffer[mInputPtr++];
          }
          return c;
      }
  
      /**
       * Method called when a CR has been spotted in input; checks if next
       * char is LF, and if so, skips it. Note that next character has to
       * come from the current input source, to qualify; it can never come
       * from another (nested) input source.
       *
       * @return True, if passed in char is '\r' and next one is '\n'.
       */
      protected final boolean skipCRLF(char c) 
          throws XMLStreamException
      {
          boolean result;
  
          if (c == '\r' && peekNext() == '\n') {
              ++mInputPtr;
              result = true;
          } else {
              result = false;
          }
          ++mCurrInputRow;
          mCurrInputRowStart = mInputPtr;
          return result;
      }
  
      protected final void markLF() {
          ++mCurrInputRow;
          mCurrInputRowStart = mInputPtr;
      }
  
      protected final void markLF(int inputPtr) {
          ++mCurrInputRow;
          mCurrInputRowStart = inputPtr;
      }
  
      /**
       * Method to push back last character read; can only be called once,
       * that is, no more than one char can be guaranteed to be succesfully
       * returned.
       */
      protected final void pushback() { --mInputPtr; }
  
      /*
      ///////////////////////////////////////////////////////////
      // Sub-class overridable input handling methods
      ///////////////////////////////////////////////////////////
       */
  
      /**
       * Method called when an entity has been expanded (new input source
       * has been created). Needs to initialize location information and change
       * active input source.
       *
       * @param entityId Name of the entity being expanded
       */
      protected void initInputSource(WstxInputSource newInput, boolean isExt,
                                     String entityId)
          throws XMLStreamException
      {
          mInput = newInput;
          // Let's make sure new input will be read next time input is needed:
          mInputPtr = 0;
          mInputEnd = 0;
          /* Plus, reset the input location so that'll be accurate for
           * error reporting etc.
           */
          mInputTopDepth = mCurrDepth;
          mInput.initInputLocation(this, mCurrDepth);
  
          /* 21-Feb-2006, TSa: Linefeeds are NOT normalized when expanding
           *   internal entities (XML, 2.11)
           */
          if (isExt) {
              mNormalizeLFs = true;
          } else {
              mNormalizeLFs = false;
          }
      }
  
      /**
       * Method that will try to read one or more characters from currently
       * open input sources; closing input sources if necessary.
       *
       * @return true if reading succeeded (or may succeed), false if
       *   we reached EOF.
       */
      protected boolean loadMore()
          throws XMLStreamException
      {
          WstxInputSource input = mInput;
          do {
              /* Need to make sure offsets are properly updated for error
               * reporting purposes, and do this now while previous amounts
               * are still known.
               */
              mCurrInputProcessed += mInputEnd;
              mCurrInputRowStart -= mInputEnd;
              int count;
              try {
                  count = input.readInto(this);
                  if (count > 0) {
                      return true;
                  }
                  input.close();
              } catch (IOException ioe) {
                  throw constructFromIOE(ioe);
              }
              if (input == mRootInput) {
                  /* Note: no need to check entity/input nesting in this
                   * particular case, since it will be handled by higher level
                   * parsing code (results in an unexpected EOF)
                   */
                  return false;
              }
              WstxInputSource parent = input.getParent();
              if (parent == null) { // sanity check!
                  throwNullParent(input);
              }
              /* 13-Feb-2006, TSa: Ok, do we violate a proper nesting constraints
               *   with this input block closure?
               */
              if (mCurrDepth != input.getScopeId()) {
                  handleIncompleteEntityProblem(input);
              }
  
              mInput = input = parent;
              input.restoreContext(this);
              mInputTopDepth = input.getScopeId();
              /* 21-Feb-2006, TSa: Since linefeed normalization needs to be
               *   suppressed for internal entity expansion, we may need to
               *   change the state...
               */
              if (!mNormalizeLFs) {
                  mNormalizeLFs = !input.fromInternalEntity();
              }
              // Maybe there are leftovers from that input in buffer now?
          } while (mInputPtr >= mInputEnd);
  
          return true;
      }
  
      protected final boolean loadMore(String errorMsg)
          throws XMLStreamException
      {
          if (!loadMore()) {
              throwUnexpectedEOF(errorMsg);
          }
          return true;
      }
  
      protected boolean loadMoreFromCurrent()
          throws XMLStreamException
      {
          // Need to update offsets properly
          mCurrInputProcessed += mInputEnd;
          mCurrInputRowStart -= mInputEnd;
          try {
              int count = mInput.readInto(this);
              return (count > 0);
          } catch (IOException ie) {
              throw constructFromIOE(ie);
          }
      }
  
      protected final boolean loadMoreFromCurrent(String errorMsg)
          throws XMLStreamException
      {
          if (!loadMoreFromCurrent()) {
              throwUnexpectedEOB(errorMsg);
          }
          return true;
      }
  
      /**
       * Method called to make sure current main-level input buffer has at
       * least specified number of characters available consequtively,
       * without having to call {@link #loadMore}. It can only be called
       * when input comes from main-level buffer; further, call can shift
       * content in input buffer, so caller has to flush any data still
       * pending. In short, caller has to know exactly what it's doing. :-)
       *<p>
       * Note: method does not check for any other input sources than the
       * current one -- if current source can not fulfill the request, a
       * failure is indicated.
       *
       * @return true if there's now enough data; false if not (EOF)
       */
      protected boolean ensureInput(int minAmount)
          throws XMLStreamException
      {
          int currAmount = mInputEnd - mInputPtr;
          if (currAmount >= minAmount) {
              return true;
          }
          try {
              return mInput.readMore(this, minAmount);
          } catch (IOException ie) {
              throw constructFromIOE(ie);
          }
      }
  
      protected void closeAllInput(boolean force)
          throws XMLStreamException
      {
          WstxInputSource input = mInput;
          while (true) {
              try {
                  if (force) {
                      input.closeCompletely();
                  } else {
                      input.close();
                  }
              } catch (IOException ie) {
                  throw constructFromIOE(ie);
              }
              if (input == mRootInput) {
                  break;
              }
              WstxInputSource parent = input.getParent();
              if (parent == null) { // sanity check!
                  throwNullParent(input);
              }
              mInput = input = parent;
          }
      }
  
      protected void throwNullParent(WstxInputSource curr)
      {
          throw new IllegalStateException(ErrorConsts.ERR_INTERNAL);
          //throw new IllegalStateException("Internal error: null parent for input source '"+curr+"'; should never occur (should have stopped at root input '"+mRootInput+"').");
      }
  
      /*
      ///////////////////////////////////////////////////////////
      // Entity resolution
      ///////////////////////////////////////////////////////////
       */
  
      /**
       * Method that tries to resolve a character entity, or (if caller so
       * specifies), a pre-defined internal entity (lt, gt, amp, apos, quot).
       * It will succeed iff:
       * <ol>
       *  <li>Entity in question is a simple character entity (either one of
       *    5 pre-defined ones, or using decimal/hex notation), AND
       *   <li>
       *  <li>Entity fits completely inside current input buffer.
       *   <li>
       * </ol>
       * If so, character value of entity is returned. Character 0 is returned
       * otherwise; if so, caller needs to do full resolution.
       *<p>
       * Note: On entry we are guaranteed there are at least 3 more characters
       * in this buffer; otherwise we shouldn't be called.
       *
       * @param checkStd If true, will check pre-defined internal entities
       *   (gt, lt, amp, apos, quot); if false, will only check actual
       *   character entities.
       *
       * @return (Valid) character value, if entity is a character reference,
       *   and could be resolved from current input buffer (does not span
       *   buffer boundary); null char (code 0) if not (either non-char
       *   entity, or spans input buffer boundary).
       */
      protected int resolveSimpleEntity(boolean checkStd)
          throws XMLStreamException
      {
          char[] buf = mInputBuffer;
          int ptr = mInputPtr;
          char c = buf[ptr++];
  
          // Numeric reference?
          if (c == '#') {
              c = buf[ptr++];
              int value = 0;
              int inputLen = mInputEnd;
              if (c == 'x') { // hex
                  while (ptr < inputLen) {
                      c = buf[ptr++];
                      if (c == ';') {
                          break;
                      }
                      value = value << 4;
                      if (c <= '9' && c >= '0') {
                          value += (c - '0');
                      } else if (c >= 'a' && c <= 'f') {
                          value += (10 + (c - 'a'));
                      } else if (c >= 'A' && c <= 'F') {
                          value += (10 + (c - 'A'));
                      } else {
                          mInputPtr = ptr; // so error points to correct char
                          throwUnexpectedChar(c, "; expected a hex digit (0-9a-fA-F).");
                      }
                      /* Need to check for overflow; easiest to do right as
                       * it happens...
                       */
                      if (value > MAX_UNICODE_CHAR) {
                          reportUnicodeOverflow();
                      }
                  }
              } else { // numeric (decimal)
                  while (c != ';') {
                      if (c <= '9' && c >= '0') {
                          value = (value * 10) + (c - '0');
                          // Overflow?
                          if (value > MAX_UNICODE_CHAR) {
                              reportUnicodeOverflow();
                          }
                      } else {
                          mInputPtr = ptr; // so error points to correct char
                          throwUnexpectedChar(c, "; expected a decimal number.");
                      }
                      if (ptr >= inputLen) {
                          break;
                      }
                      c = buf[ptr++];
                  }
              }
              /* We get here either if we got it all, OR if we ran out of
               * input in current buffer.
               */
              if (c == ';') { // got the full thing
                  mInputPtr = ptr;
                  validateChar(value);
                  return value;
              }
  
              /* If we ran out of input, need to just fall back, gets
               * resolved via 'full' resolution mechanism.
               */
          } else if (checkStd) {
              /* Caller may not want to resolve these quite yet...
               * (when it wants separate events for non-char entities)
               */
              if (c == 'a') { // amp or apos?
                  c = buf[ptr++];
                  
                  if (c == 'm') { // amp?
                      if (buf[ptr++] == 'p') {
                          if (ptr < mInputEnd && buf[ptr++] == ';') {
                              mInputPtr = ptr;
                              return '&';
                          }
                      }
                  } else if (c == 'p') { // apos?
                      if (buf[ptr++] == 'o') {
                          int len = mInputEnd;
                          if (ptr < len && buf[ptr++] == 's') {
                              if (ptr < len && buf[ptr++] == ';') {
                                  mInputPtr = ptr;
                                  return '\'';
                              }
                          }
                      }
                  }
              } else if (c == 'g') { // gt?
                  if (buf[ptr++] == 't' && buf[ptr++] == ';') {
                      mInputPtr = ptr;
                      return '>';
                  }
              } else if (c == 'l') { // lt?
                  if (buf[ptr++] == 't' && buf[ptr++] == ';') {
                      mInputPtr = ptr;
                      return '<';
                  }
              } else if (c == 'q') { // quot?
                  if (buf[ptr++] == 'u' && buf[ptr++] == 'o') {
                      int len = mInputEnd;
                      if (ptr < len && buf[ptr++] == 't') {
                          if (ptr < len && buf[ptr++] == ';') {
                              mInputPtr = ptr;
                              return '"';
                          }
                      }
                  }
              }
          }
          return 0;
      }
  
      /**
       * Method called to resolve character entities, and only character
       * entities (except that pre-defined char entities -- amp, apos, lt,
       * gt, quote -- MAY be "char entities" in this sense, depending on
       * arguments).
       * Otherwise it is to return the null char; if so,
       * the input pointer will point to the same point as when method
       * entered (char after ampersand), plus the ampersand itself is
       * guaranteed to be in the input buffer (so caller can just push it
       * back if necessary).
       *<p>
       * Most often this method is called when reader is not to expand
       * non-char entities automatically, but to return them as separate
       * events.
       *<p>
       * Main complication here is that we need to do 5-char lookahead. This
       * is problematic if chars are on input buffer boundary. This is ok
       * for the root level input buffer, but not for some nested buffers.
       * However, according to XML specs, such split entities are actually
       * illegal... so we can throw an exception in those cases.
       *
       * @param checkStd If true, will check pre-defined internal entities
       *   (gt, lt, amp, apos, quot) as character entities; if false, will only
       *   check actual 'real' character entities.
       *
       * @return (Valid) character value, if entity is a character reference,
       *   and could be resolved from current input buffer (does not span
       *   buffer boundary); null char (code 0) if not (either non-char
       *   entity, or spans input buffer boundary).
       */
      protected int resolveCharOnlyEntity(boolean checkStd)
          throws XMLStreamException
      {
          //int avail = inputInBuffer();
          int avail = mInputEnd - mInputPtr;
          if (avail < 6) {
              // split entity, or buffer boundary
              /* Don't want to lose leading '&' (in case we can not expand
               * the entity), so let's push it back first
               */
              --mInputPtr;
              /* Shortest valid reference would be 3 chars ('&a;'); which
               * would only be legal from an expanded entity...
               */
              if (!ensureInput(6)) {
                  avail = inputInBuffer();
                  if (avail < 3) {
                      throwUnexpectedEOF(SUFFIX_IN_ENTITY_REF);
                  }
              } else {
                  avail = 6;
              }
              // ... and now we can move pointer back as well:
              ++mInputPtr;
          }
  
          /* Ok, now we have one more character to check, and that's enough
           * to determine type decisively.
           */
          char c = mInputBuffer[mInputPtr];
  
          // A char reference?
          if (c == '#') { // yup
              ++mInputPtr;
              return resolveCharEnt(null);
          }
  
          // nope... except may be a pre-def?
          if (checkStd) {
              if (c == 'a') {
                  char d = mInputBuffer[mInputPtr+1];
                  if (d == 'm') {
                      if (avail >= 4
                          && mInputBuffer[mInputPtr+2] == 'p'
                          && mInputBuffer[mInputPtr+3] == ';') {
                          mInputPtr += 4;
                          return '&';
                      }
                  } else if (d == 'p') {
                      if (avail >= 5
                          && mInputBuffer[mInputPtr+2] == 'o'
                          && mInputBuffer[mInputPtr+3] == 's'
                          && mInputBuffer[mInputPtr+4] == ';') {
                          mInputPtr += 5;
                          return '\'';
                      }
                  }
              } else if (c == 'l') {
                  if (avail >= 3
                      && mInputBuffer[mInputPtr+1] == 't'
                      && mInputBuffer[mInputPtr+2] == ';') {
                      mInputPtr += 3;
                      return '<';
                  }
              } else if (c == 'g') {
                  if (avail >= 3
                      && mInputBuffer[mInputPtr+1] == 't'
                      && mInputBuffer[mInputPtr+2] == ';') {
                      mInputPtr += 3;
                      return '>';
                  }
              } else if (c == 'q') {
                  if (avail >= 5
                      && mInputBuffer[mInputPtr+1] == 'u'
                      && mInputBuffer[mInputPtr+2] == 'o'
                      && mInputBuffer[mInputPtr+3] == 't'
                      && mInputBuffer[mInputPtr+4] == ';') {
                      mInputPtr += 5;
                      return '"';
                  }
              }
          }
          return 0;
      }
  
      /**
       * Reverse of {@link #resolveCharOnlyEntity}; will only resolve entity
       * if it is NOT a character entity (or pre-defined 'generic' entity;
       * amp, apos, lt, gt or quot). Only used in cases where entities
       * are to be separately returned unexpanded (in non-entity-replacing
       * mode); which means it's never called from dtd handler.
       */
      protected EntityDecl resolveNonCharEntity()
          throws XMLStreamException
      {
          //int avail = inputInBuffer();
          int avail = mInputEnd - mInputPtr;
          if (avail < 6) {
              // split entity, or buffer boundary
              /* Don't want to lose leading '&' (in case we can not expand
               * the entity), so let's push it back first
               */
              --mInputPtr;
  
              /* Shortest valid reference would be 3 chars ('&a;'); which
               * would only be legal from an expanded entity...
               */
              if (!ensureInput(6)) {
                  avail = inputInBuffer();
                  if (avail < 3) {
                      throwUnexpectedEOF(SUFFIX_IN_ENTITY_REF);
                  }
              } else {
                  avail = 6;
              }
              // ... and now we can move pointer back as well:
              ++mInputPtr;
          }
  
          // We don't care about char entities:
          char c = mInputBuffer[mInputPtr];
          if (c == '#') {
              return null;
          }
  
          /* 19-Aug-2004, TSa: Need special handling for pre-defined
           *   entities; they are not counted as 'real' general parsed
           *   entities, but more as character entities...
           */
  
          // have chars at least up to mInputPtr+4 by now
          if (c == 'a') {
              char d = mInputBuffer[mInputPtr+1];
              if (d == 'm') {
                  if (avail >= 4
                      && mInputBuffer[mInputPtr+2] == 'p'
                      && mInputBuffer[mInputPtr+3] == ';') {
                      // If not automatically expanding:
                      //return sEntityAmp;
                      // mInputPtr += 4;
                      return null;
                  }
              } else if (d == 'p') {
                  if (avail >= 5
                      && mInputBuffer[mInputPtr+2] == 'o'
                      && mInputBuffer[mInputPtr+3] == 's'
                      && mInputBuffer[mInputPtr+4] == ';') {
                      return null;
                  }
              }
          } else if (c == 'l') {
              if (avail >= 3
                  && mInputBuffer[mInputPtr+1] == 't'
                  && mInputBuffer[mInputPtr+2] == ';') {
                  return null;
              }
          } else if (c == 'g') {
              if (avail >= 3
                  && mInputBuffer[mInputPtr+1] == 't'
                  && mInputBuffer[mInputPtr+2] == ';') {
                  return null;
              }
          } else if (c == 'q') {
              if (avail >= 5
                  && mInputBuffer[mInputPtr+1] == 'u'
                  && mInputBuffer[mInputPtr+2] == 'o'
                  && mInputBuffer[mInputPtr+3] == 't'
                  && mInputBuffer[mInputPtr+4] == ';') {
                  return null;
              }
          }
  
          // Otherwise, let's just parse in generic way:
          ++mInputPtr; // since we already read the first letter
          String id = parseEntityName(c);
          mCurrName = id;
  
  