| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 1999,2000 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xerces" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 1999, International |
| * Business Machines, Inc., http://www.apache.org. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| package org.apache.xerces.readers; |
| |
| import org.apache.xerces.framework.XMLErrorReporter; |
| import org.apache.xerces.utils.QName; |
| import org.apache.xerces.utils.StringPool; |
| import org.apache.xerces.utils.XMLCharacterProperties; |
| |
| import org.xml.sax.Locator; |
| import org.xml.sax.InputSource; |
| import java.io.IOException; |
| |
| /** |
| * Reader for processing internal entity replacement text. |
| * <p> |
| * This reader processes data contained within strings kept |
| * in the string pool. It provides the support for both |
| * general and parameter entities. The location support |
| * as we are processing the replacement text is somewhat |
| * poor and needs to be updated when "nested locations" |
| * have been implemented. |
| * <p> |
| * For efficiency, we return instances of this class to a |
| * free list and reuse those instances to process other |
| * strings. |
| * |
| * @version $id$ |
| */ |
| final class StringReader extends XMLEntityReader { |
| /** |
| * Allocate a string reader |
| * |
| * @param entityHandler The current entity handler. |
| * @param errorReporter The current error reporter. |
| * @param sendCharDataAsCharArray true if char data should be reported using |
| * char arrays instead of string handles. |
| * @param lineNumber The line number to return as our position. |
| * @param columnNumber The column number to return as our position. |
| * @param stringHandle The StringPool handle for the data to process. |
| * @param stringPool The string pool. |
| * @param addEnclosingSpaces If true, treat the data to process as if |
| * there were a leading and trailing space |
| * character enclosing the string data. |
| * @return The reader that will process the string data. |
| */ |
| public static StringReader createStringReader(XMLEntityHandler entityHandler, |
| XMLErrorReporter errorReporter, |
| boolean sendCharDataAsCharArray, |
| int lineNumber, |
| int columnNumber, |
| int stringHandle, |
| StringPool stringPool, |
| boolean addEnclosingSpaces) |
| { |
| StringReader reader = null; |
| synchronized (StringReader.class) { |
| reader = fgFreeReaders; |
| if (reader == null) { |
| return new StringReader(entityHandler, errorReporter, sendCharDataAsCharArray, lineNumber, columnNumber, |
| stringHandle, stringPool, addEnclosingSpaces); |
| } |
| fgFreeReaders = reader.fNextFreeReader; |
| } |
| reader.init(entityHandler, errorReporter, sendCharDataAsCharArray, lineNumber, columnNumber, |
| stringHandle, stringPool, addEnclosingSpaces); |
| return reader; |
| } |
| // |
| // |
| // |
| private StringReader(XMLEntityHandler entityHandler, XMLErrorReporter errorReporter, |
| boolean sendCharDataAsCharArray, int lineNumber, int columnNumber, |
| int stringHandle, StringPool stringPool, boolean addEnclosingSpaces) |
| { |
| super(entityHandler, errorReporter, sendCharDataAsCharArray, lineNumber, columnNumber); |
| fStringPool = stringPool; |
| fData = fStringPool.toString(stringHandle); |
| fCurrentOffset = 0; |
| fEndOffset = fData.length(); |
| if (addEnclosingSpaces) { |
| fMostRecentChar = ' '; |
| fCurrentOffset--; |
| oweTrailingSpace = hadTrailingSpace = true; |
| } else { |
| fMostRecentChar = fEndOffset == 0 ? -1 : fData.charAt(0); |
| } |
| } |
| private void init(XMLEntityHandler entityHandler, XMLErrorReporter errorReporter, |
| boolean sendCharDataAsCharArray, int lineNumber, int columnNumber, |
| int stringHandle, StringPool stringPool, boolean addEnclosingSpaces) |
| { |
| super.init(entityHandler, errorReporter, sendCharDataAsCharArray, lineNumber, columnNumber); |
| fStringPool = stringPool; |
| fData = fStringPool.toString(stringHandle); |
| fCurrentOffset = 0; |
| fEndOffset = fData.length(); |
| fNextFreeReader = null; |
| if (addEnclosingSpaces) { |
| fMostRecentChar = ' '; |
| fCurrentOffset--; |
| oweTrailingSpace = hadTrailingSpace = true; |
| } else { |
| fMostRecentChar = fEndOffset == 0 ? -1 : fData.charAt(0); |
| oweTrailingSpace = hadTrailingSpace = false; |
| } |
| } |
| // |
| // |
| // |
| public int addString(int offset, int length) { |
| if (length == 0) |
| return 0; |
| return fStringPool.addString(fData.substring(offset, offset + length)); |
| } |
| // |
| // |
| // |
| public int addSymbol(int offset, int length) { |
| if (length == 0) |
| return 0; |
| return fStringPool.addSymbol(fData.substring(offset, offset + length)); |
| } |
| // |
| // |
| // |
| public void append(XMLEntityHandler.CharBuffer charBuffer, int offset, int length) { |
| boolean addSpace = false; |
| for (int i = 0; i < length; i++) { |
| try { |
| charBuffer.append(fData.charAt(offset++)); |
| } catch (StringIndexOutOfBoundsException ex) { |
| if (offset == fEndOffset + 1 && hadTrailingSpace) { |
| charBuffer.append(' '); |
| } else { |
| System.err.println("StringReader.append()"); |
| throw ex; |
| } |
| } |
| } |
| } |
| // |
| // |
| // |
| private int loadNextChar() { |
| if (++fCurrentOffset >= fEndOffset) { |
| if (oweTrailingSpace) { |
| oweTrailingSpace = false; |
| fMostRecentChar = ' '; |
| } else { |
| fMostRecentChar = -1; |
| } |
| } else { |
| fMostRecentChar = fData.charAt(fCurrentOffset); |
| } |
| return fMostRecentChar; |
| } |
| // |
| // |
| // |
| public XMLEntityHandler.EntityReader changeReaders() throws Exception { |
| XMLEntityHandler.EntityReader nextReader = super.changeReaders(); |
| synchronized (StringReader.class) { |
| fNextFreeReader = fgFreeReaders; |
| fgFreeReaders = this; |
| } |
| return nextReader; |
| } |
| // |
| // |
| // |
| public boolean lookingAtChar(char chr, boolean skipPastChar) throws Exception { |
| int ch = fMostRecentChar; |
| if (ch != chr) { |
| if (ch == -1) { |
| return changeReaders().lookingAtChar(chr, skipPastChar); |
| } |
| return false; |
| } |
| if (skipPastChar) { |
| if (++fCurrentOffset >= fEndOffset) { |
| if (oweTrailingSpace) { |
| oweTrailingSpace = false; |
| fMostRecentChar = ' '; |
| } else { |
| fMostRecentChar = -1; |
| } |
| } else { |
| fMostRecentChar = fData.charAt(fCurrentOffset); |
| } |
| } |
| return true; |
| } |
| // |
| // |
| // |
| public boolean lookingAtValidChar(boolean skipPastChar) throws Exception { |
| int ch = fMostRecentChar; |
| if (ch < 0xD800) { |
| if (ch < 0x20 && ch != 0x09 && ch != 0x0A && ch != 0x0D) { |
| if (ch == -1) |
| return changeReaders().lookingAtValidChar(skipPastChar); |
| return false; |
| } |
| if (skipPastChar) { |
| if (++fCurrentOffset >= fEndOffset) { |
| if (oweTrailingSpace) { |
| oweTrailingSpace = false; |
| fMostRecentChar = ' '; |
| } else { |
| fMostRecentChar = -1; |
| } |
| } else { |
| fMostRecentChar = fData.charAt(fCurrentOffset); |
| } |
| } |
| return true; |
| } |
| if (ch > 0xFFFD) { |
| return false; |
| } |
| if (ch < 0xDC00) { |
| if (fCurrentOffset + 1 >= fEndOffset) { |
| return false; |
| } |
| ch = fData.charAt(fCurrentOffset + 1); |
| if (ch < 0xDC00 || ch >= 0xE000) { |
| return false; |
| } else if (!skipPastChar) { |
| return true; |
| } else { |
| fCurrentOffset++; |
| } |
| } else if (ch < 0xE000) { |
| return false; |
| } |
| if (skipPastChar) { |
| if (++fCurrentOffset >= fEndOffset) { |
| if (oweTrailingSpace) { |
| oweTrailingSpace = false; |
| fMostRecentChar = ' '; |
| } else { |
| fMostRecentChar = -1; |
| } |
| } else { |
| fMostRecentChar = fData.charAt(fCurrentOffset); |
| } |
| } |
| return true; |
| } |
| // |
| // |
| // |
| public boolean lookingAtSpace(boolean skipPastChar) throws Exception { |
| int ch = fMostRecentChar; |
| if (ch > 0x20) |
| return false; |
| if (ch == 0x20 || ch == 0x0A || ch == 0x0D || ch == 0x09) { |
| if (skipPastChar) { |
| loadNextChar(); |
| } |
| return true; |
| } |
| if (ch == -1) { |
| return changeReaders().lookingAtSpace(skipPastChar); |
| } |
| return false; |
| } |
| // |
| // |
| // |
| public void skipToChar(char chr) throws Exception { |
| // |
| // REVISIT - this will skip invalid characters without reporting them. |
| // |
| int ch = fMostRecentChar; |
| while (true) { |
| if (ch == chr) |
| return; |
| if (ch == -1) { |
| changeReaders().skipToChar(chr); |
| return; |
| } |
| ch = loadNextChar(); |
| } |
| } |
| // |
| // |
| // |
| public void skipPastSpaces() throws Exception { |
| int ch = fMostRecentChar; |
| if (ch == -1) { |
| changeReaders().skipPastSpaces(); |
| return; |
| } |
| while (true) { |
| if (ch > 0x20 || (ch != 0x20 && ch != 0x0A && ch != 0x09 && ch != 0x0D)) { |
| fMostRecentChar = ch; |
| return; |
| } |
| if (++fCurrentOffset >= fEndOffset) { |
| changeReaders().skipPastSpaces(); |
| return; |
| } |
| ch = fData.charAt(fCurrentOffset); |
| } |
| } |
| // |
| // |
| // |
| public void skipPastName(char fastcheck) throws Exception { |
| int ch = fMostRecentChar; |
| if (ch < 0x80) { |
| if (ch == -1 || XMLCharacterProperties.fgAsciiInitialNameChar[ch] == 0) |
| return; |
| } else { |
| if (!fCalledCharPropInit) { |
| XMLCharacterProperties.initCharFlags(); |
| fCalledCharPropInit = true; |
| } |
| if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_InitialNameCharFlag) == 0) |
| return; |
| } |
| while (true) { |
| ch = loadNextChar(); |
| if (fastcheck == ch) |
| return; |
| if (ch < 0x80) { |
| if (ch == -1 || XMLCharacterProperties.fgAsciiNameChar[ch] == 0) |
| return; |
| } else { |
| if (!fCalledCharPropInit) { |
| XMLCharacterProperties.initCharFlags(); |
| fCalledCharPropInit = true; |
| } |
| if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_NameCharFlag) == 0) |
| return; |
| } |
| } |
| } |
| // |
| // |
| // |
| public void skipPastNmtoken(char fastcheck) throws Exception { |
| int ch = fMostRecentChar; |
| while (true) { |
| if (fastcheck == ch) |
| return; |
| if (ch < 0x80) { |
| if (ch == -1 || XMLCharacterProperties.fgAsciiNameChar[ch] == 0) |
| return; |
| } else { |
| if (!fCalledCharPropInit) { |
| XMLCharacterProperties.initCharFlags(); |
| fCalledCharPropInit = true; |
| } |
| if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_NameCharFlag) == 0) |
| return; |
| } |
| ch = loadNextChar(); |
| } |
| } |
| // |
| // |
| // |
| public boolean skippedString(char[] s) throws Exception { |
| int ch = fMostRecentChar; |
| if (ch != s[0]) { |
| if (ch == -1) |
| return changeReaders().skippedString(s); |
| return false; |
| } |
| if (fCurrentOffset + s.length > fEndOffset) |
| return false; |
| for (int i = 1; i < s.length; i++) { |
| if (fData.charAt(fCurrentOffset + i) != s[i]) |
| return false; |
| } |
| fCurrentOffset += (s.length - 1); |
| loadNextChar(); |
| return true; |
| } |
| // |
| // |
| // |
| public int scanInvalidChar() throws Exception { |
| int ch = fMostRecentChar; |
| if (ch == -1) |
| return changeReaders().scanInvalidChar(); |
| loadNextChar(); |
| return ch; |
| } |
| // |
| // |
| // |
| public int scanCharRef(boolean hex) throws Exception { |
| int ch = fMostRecentChar; |
| if (ch == -1) |
| return changeReaders().scanCharRef(hex); |
| int num = 0; |
| if (hex) { |
| if (ch > 'f' || XMLCharacterProperties.fgAsciiXDigitChar[ch] == 0) |
| return XMLEntityHandler.CHARREF_RESULT_INVALID_CHAR; |
| num = ch - (ch < 'A' ? '0' : (ch < 'a' ? 'A' : 'a') - 10); |
| } else { |
| if (ch < '0' || ch > '9') |
| return XMLEntityHandler.CHARREF_RESULT_INVALID_CHAR; |
| num = ch - '0'; |
| } |
| boolean toobig = false; |
| while (true) { |
| ch = loadNextChar(); |
| if (ch == -1) |
| return XMLEntityHandler.CHARREF_RESULT_SEMICOLON_REQUIRED; |
| if (hex) { |
| if (ch > 'f' || XMLCharacterProperties.fgAsciiXDigitChar[ch] == 0) |
| break; |
| } else { |
| if (ch < '0' || ch > '9') |
| break; |
| } |
| if (hex) { |
| int dig = ch - (ch < 'A' ? '0' : (ch < 'a' ? 'A' : 'a') - 10); |
| num = (num << 4) + dig; |
| } else { |
| int dig = ch - '0'; |
| num = (num * 10) + dig; |
| } |
| if (num > 0x10FFFF) { |
| toobig = true; |
| num = 0; |
| } |
| } |
| if (ch != ';') |
| return XMLEntityHandler.CHARREF_RESULT_SEMICOLON_REQUIRED; |
| loadNextChar(); |
| if (toobig) |
| return XMLEntityHandler.CHARREF_RESULT_OUT_OF_RANGE; |
| return num; |
| } |
| // |
| // |
| // |
| public int scanStringLiteral() throws Exception { |
| boolean single; |
| if (!(single = lookingAtChar('\'', true)) && !lookingAtChar('\"', true)) { |
| return XMLEntityHandler.STRINGLIT_RESULT_QUOTE_REQUIRED; |
| } |
| int offset = fCurrentOffset; |
| char qchar = single ? '\'' : '\"'; |
| while (!lookingAtChar(qchar, false)) { |
| if (!lookingAtValidChar(true)) { |
| return XMLEntityHandler.STRINGLIT_RESULT_INVALID_CHAR; |
| } |
| } |
| int stringIndex = addString(offset, fCurrentOffset - offset); |
| lookingAtChar(qchar, true); // move past qchar |
| return stringIndex; |
| } |
| // |
| // [10] AttValue ::= '"' ([^<&"] | Reference)* '"' |
| // | "'" ([^<&'] | Reference)* "'" |
| // |
| public int scanAttValue(char qchar, boolean asSymbol) throws Exception |
| { |
| int offset = fCurrentOffset; |
| while (true) { |
| if (lookingAtChar(qchar, false)) { |
| break; |
| } |
| if (lookingAtChar(' ', true)) { |
| continue; |
| } |
| if (lookingAtSpace(false)) { |
| return XMLEntityHandler.ATTVALUE_RESULT_COMPLEX; |
| } |
| if (lookingAtChar('&', false)) { |
| return XMLEntityHandler.ATTVALUE_RESULT_COMPLEX; |
| } |
| if (lookingAtChar('<', false)) { |
| return XMLEntityHandler.ATTVALUE_RESULT_LESSTHAN; |
| } |
| if (!lookingAtValidChar(true)) { |
| return XMLEntityHandler.ATTVALUE_RESULT_INVALID_CHAR; |
| } |
| } |
| int result = asSymbol ? addSymbol(offset, fCurrentOffset - offset) : addString(offset, fCurrentOffset - offset); |
| lookingAtChar(qchar, true); |
| return result; |
| } |
| // |
| // [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' |
| // | "'" ([^%&'] | PEReference | Reference)* "'" |
| // |
| // The values in the following table are defined as: |
| // |
| // 0 - not special |
| // 1 - quote character |
| // 2 - reference |
| // 3 - peref |
| // 4 - invalid |
| // |
| public static final byte fgAsciiEntityValueChar[] = { |
| 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 4, 4, 0, 4, 4, |
| 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
| 0, 0, 1, 0, 0, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, // '\"', '%', '&', '\'' |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
| }; |
| public int scanEntityValue(int qchar, boolean createString) throws Exception |
| { |
| int offset = fCurrentOffset; |
| int ch = fMostRecentChar; |
| while (true) { |
| if (ch == -1) { |
| changeReaders(); // do not call next reader, our caller may need to change the parameters |
| return XMLEntityHandler.ENTITYVALUE_RESULT_END_OF_INPUT; |
| } |
| if (ch < 0x80) { |
| switch (fgAsciiEntityValueChar[ch]) { |
| case 1: // quote char |
| if (ch == qchar) { |
| if (!createString) |
| return XMLEntityHandler.ENTITYVALUE_RESULT_FINISHED; |
| int length = fCurrentOffset - offset; |
| int result = length == 0 ? StringPool.EMPTY_STRING : addString(offset, length); |
| loadNextChar(); |
| return result; |
| } |
| // the other quote character is not special |
| // fall through |
| case 0: // non-special char |
| if (++fCurrentOffset >= fEndOffset) { |
| if (oweTrailingSpace) { |
| oweTrailingSpace = false; |
| ch = fMostRecentChar = ' '; |
| } else { |
| ch = fMostRecentChar = -1; |
| } |
| } else { |
| ch = fMostRecentChar = fData.charAt(fCurrentOffset); |
| } |
| continue; |
| case 2: // reference |
| return XMLEntityHandler.ENTITYVALUE_RESULT_REFERENCE; |
| case 3: // peref |
| return XMLEntityHandler.ENTITYVALUE_RESULT_PEREF; |
| case 4: // invalid |
| return XMLEntityHandler.ENTITYVALUE_RESULT_INVALID_CHAR; |
| } |
| } else if (ch < 0xD800) { |
| ch = loadNextChar(); |
| } else if (ch >= 0xE000 && (ch <= 0xFFFD || (ch >= 0x10000 && ch <= 0x10FFFF))) { |
| // |
| // REVISIT - needs more code to check surrogates. |
| // |
| ch = loadNextChar(); |
| } else { |
| return XMLEntityHandler.ENTITYVALUE_RESULT_INVALID_CHAR; |
| } |
| } |
| } |
| // |
| // |
| // |
| public boolean scanExpectedName(char fastcheck, StringPool.CharArrayRange expectedName) throws Exception { |
| int ch = fMostRecentChar; |
| if (ch == -1) { |
| return changeReaders().scanExpectedName(fastcheck, expectedName); |
| } |
| if (!fCalledCharPropInit) { |
| XMLCharacterProperties.initCharFlags(); |
| fCalledCharPropInit = true; |
| } |
| int nameOffset = fCurrentOffset; |
| if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_InitialNameCharFlag) == 0) |
| return false; |
| while (true) { |
| ch = loadNextChar(); |
| if (fastcheck == ch) |
| break; |
| if (ch == -1) |
| break; |
| if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_NameCharFlag) == 0) |
| break; |
| } |
| int nameIndex = fStringPool.addSymbol(fData.substring(nameOffset, fCurrentOffset)); |
| // DEFECT !! check name against expected name |
| |
| return true; |
| } |
| // |
| // |
| // |
| public void scanQName(char fastcheck, QName qname) throws Exception { |
| int ch = fMostRecentChar; |
| if (ch == -1) { |
| changeReaders().scanQName(fastcheck, qname); |
| return; |
| } |
| if (!fCalledCharPropInit) { |
| XMLCharacterProperties.initCharFlags(); |
| fCalledCharPropInit = true; |
| } |
| int nameOffset = fCurrentOffset; |
| if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_InitialNameCharFlag) == 0) { |
| qname.clear(); |
| return; |
| } |
| while (true) { |
| ch = loadNextChar(); |
| if (fastcheck == ch) |
| break; |
| if (ch == -1) |
| break; |
| if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_NameCharFlag) == 0) |
| break; |
| } |
| |
| qname.clear(); |
| qname.rawname = fStringPool.addSymbol(fData.substring(nameOffset, fCurrentOffset)); |
| |
| int index = fData.indexOf(':', nameOffset); |
| if (index != -1) { |
| qname.prefix = fStringPool.addSymbol(fData.substring(nameOffset, index)); |
| int indexOfSpaceChar = fData.indexOf( ' ', index + 1 );//one past : look for blank |
| String localPart; |
| if( indexOfSpaceChar != -1 ){//found one |
| localPart = fData.substring(index+1, indexOfSpaceChar ); |
| qname.localpart = fStringPool.addSymbol(localPart); |
| } else{//then get up to end of String |
| int lenfData = fData.length(); |
| localPart = fData.substring( index + 1, lenfData ); |
| qname.localpart = fStringPool.addSymbol(localPart); |
| } |
| qname.localpart = fStringPool.addSymbol(localPart); |
| } |
| else { |
| qname.localpart = qname.rawname; |
| } |
| |
| } // scanQName(char,QName) |
| |
| // |
| // |
| // |
| public int scanName(char fastcheck) throws Exception { |
| int ch = fMostRecentChar; |
| if (ch == -1) { |
| return changeReaders().scanName(fastcheck); |
| } |
| if (!fCalledCharPropInit) { |
| XMLCharacterProperties.initCharFlags(); |
| fCalledCharPropInit = true; |
| } |
| int nameOffset = fCurrentOffset; |
| if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_InitialNameCharFlag) == 0) |
| return -1; |
| while (true) { |
| if (++fCurrentOffset >= fEndOffset) { |
| if (oweTrailingSpace) { |
| oweTrailingSpace = false; |
| fMostRecentChar = ' '; |
| } else { |
| fMostRecentChar = -1; |
| } |
| break; |
| } |
| ch = fMostRecentChar = fData.charAt(fCurrentOffset); |
| if (fastcheck == ch) |
| break; |
| if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_NameCharFlag) == 0) |
| break; |
| } |
| int nameIndex = fStringPool.addSymbol(fData.substring(nameOffset, fCurrentOffset)); |
| return nameIndex; |
| } |
| // |
| // There are no leading/trailing space checks here because scanContent cannot |
| // be called on a parameter entity reference value. |
| // |
| private int recognizeMarkup(int ch) throws Exception { |
| if (ch == -1) { |
| return XMLEntityHandler.CONTENT_RESULT_MARKUP_END_OF_INPUT; |
| } |
| switch (ch) { |
| case '?': |
| loadNextChar(); |
| return XMLEntityHandler.CONTENT_RESULT_START_OF_PI; |
| case '!': |
| ch = loadNextChar(); |
| if (ch == -1) { |
| fCurrentOffset -= 2; |
| loadNextChar(); |
| return XMLEntityHandler.CONTENT_RESULT_MARKUP_END_OF_INPUT; |
| } |
| if (ch == '-') { |
| ch = loadNextChar(); |
| if (ch == -1) { |
| fCurrentOffset -= 3; |
| loadNextChar(); |
| return XMLEntityHandler.CONTENT_RESULT_MARKUP_END_OF_INPUT; |
| } |
| if (ch == '-') { |
| loadNextChar(); |
| return XMLEntityHandler.CONTENT_RESULT_START_OF_COMMENT; |
| } |
| break; |
| } |
| if (ch == '[') { |
| for (int i = 0; i < 6; i++) { |
| ch = loadNextChar(); |
| if (ch == -1) { |
| fCurrentOffset -= (3 + i); |
| loadNextChar(); |
| return XMLEntityHandler.CONTENT_RESULT_MARKUP_END_OF_INPUT; |
| } |
| if (ch != cdata_string[i]) { |
| return XMLEntityHandler.CONTENT_RESULT_MARKUP_NOT_RECOGNIZED; |
| } |
| } |
| loadNextChar(); |
| return XMLEntityHandler.CONTENT_RESULT_START_OF_CDSECT; |
| } |
| break; |
| case '/': |
| loadNextChar(); |
| return XMLEntityHandler.CONTENT_RESULT_START_OF_ETAG; |
| default: |
| return XMLEntityHandler.CONTENT_RESULT_START_OF_ELEMENT; |
| } |
| return XMLEntityHandler.CONTENT_RESULT_MARKUP_NOT_RECOGNIZED; |
| } |
| private int recognizeReference(int ch) throws Exception { |
| if (ch == -1) { |
| return XMLEntityHandler.CONTENT_RESULT_MARKUP_END_OF_INPUT; |
| } |
| // |
| // [67] Reference ::= EntityRef | CharRef |
| // [68] EntityRef ::= '&' Name ';' |
| // [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';' |
| // |
| if (ch == '#') { |
| loadNextChar(); |
| return XMLEntityHandler.CONTENT_RESULT_START_OF_CHARREF; |
| } else { |
| return XMLEntityHandler.CONTENT_RESULT_START_OF_ENTITYREF; |
| } |
| } |
| public int scanContent(QName element) throws Exception { |
| int ch = fMostRecentChar; |
| if (ch == -1) { |
| return changeReaders().scanContent(element); |
| } |
| int offset = fCurrentOffset; |
| if (ch < 0x80) { |
| switch (XMLCharacterProperties.fgAsciiWSCharData[ch]) { |
| case 0: |
| ch = loadNextChar(); |
| break; |
| case 1: |
| ch = loadNextChar(); |
| if (!fInCDSect) { |
| return recognizeMarkup(ch); |
| } |
| break; |
| case 2: |
| ch = loadNextChar(); |
| if (!fInCDSect) { |
| return recognizeReference(ch); |
| } |
| break; |
| case 3: |
| ch = loadNextChar(); |
| if (ch == ']' && fCurrentOffset + 1 < fEndOffset && fData.charAt(fCurrentOffset + 1) == '>') { |
| loadNextChar(); |
| loadNextChar(); |
| return XMLEntityHandler.CONTENT_RESULT_END_OF_CDSECT; |
| } |
| break; |
| case 4: |
| return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR; |
| case 5: |
| do { |
| ch = loadNextChar(); |
| if (ch == -1) { |
| callCharDataHandler(offset, fEndOffset, true); |
| return changeReaders().scanContent(element); |
| } |
| } while (ch == 0x20 || ch == 0x0A || ch == 0x0D || ch == 0x09); |
| if (ch < 0x80) { |
| switch (XMLCharacterProperties.fgAsciiCharData[ch]) { |
| case 0: |
| ch = loadNextChar(); |
| break; |
| case 1: |
| ch = loadNextChar(); |
| if (!fInCDSect) { |
| callCharDataHandler(offset, fCurrentOffset - 1, true); |
| return recognizeMarkup(ch); |
| } |
| break; |
| case 2: |
| ch = loadNextChar(); |
| if (!fInCDSect) { |
| callCharDataHandler(offset, fCurrentOffset - 1, true); |
| return recognizeReference(ch); |
| } |
| break; |
| case 3: |
| ch = loadNextChar(); |
| if (ch == ']' && fCurrentOffset + 1 < fEndOffset && fData.charAt(fCurrentOffset + 1) == '>') { |
| callCharDataHandler(offset, fCurrentOffset - 1, true); |
| loadNextChar(); |
| loadNextChar(); |
| return XMLEntityHandler.CONTENT_RESULT_END_OF_CDSECT; |
| } |
| break; |
| case 4: |
| callCharDataHandler(offset, fCurrentOffset, true); |
| return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR; |
| } |
| } else { |
| if (ch == 0xFFFE || ch == 0xFFFF) { |
| callCharDataHandler(offset, fCurrentOffset, true); |
| return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR; |
| } |
| ch = loadNextChar(); |
| } |
| } |
| } else { |
| if (ch == 0xFFFE || ch == 0xFFFF) { |
| callCharDataHandler(offset, fCurrentOffset, false); |
| return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR; |
| } |
| ch = loadNextChar(); |
| } |
| while (true) { |
| if (ch == -1) { |
| callCharDataHandler(offset, fEndOffset, false); |
| return changeReaders().scanContent(element); |
| } |
| if (ch >= 0x80) |
| break; |
| if (XMLCharacterProperties.fgAsciiCharData[ch] != 0) |
| break; |
| ch = loadNextChar(); |
| } |
| while (true) { // REVISIT - EOF check ? |
| if (ch < 0x80) { |
| switch (XMLCharacterProperties.fgAsciiCharData[ch]) { |
| case 0: |
| ch = loadNextChar(); |
| break; |
| case 1: |
| ch = loadNextChar(); |
| if (!fInCDSect) { |
| callCharDataHandler(offset, fCurrentOffset - 1, false); |
| return recognizeMarkup(ch); |
| } |
| break; |
| case 2: |
| ch = loadNextChar(); |
| if (!fInCDSect) { |
| callCharDataHandler(offset, fCurrentOffset - 1, false); |
| return recognizeReference(ch); |
| } |
| break; |
| case 3: |
| ch = loadNextChar(); |
| if (ch == ']' && fCurrentOffset + 1 < fEndOffset && fData.charAt(fCurrentOffset + 1) == '>') { |
| callCharDataHandler(offset, fCurrentOffset - 1, false); |
| loadNextChar(); |
| loadNextChar(); |
| return XMLEntityHandler.CONTENT_RESULT_END_OF_CDSECT; |
| } |
| break; |
| case 4: |
| callCharDataHandler(offset, fCurrentOffset, false); |
| return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR; |
| } |
| } else { |
| if (ch == 0xFFFE || ch == 0xFFFF) { |
| callCharDataHandler(offset, fCurrentOffset, false); |
| return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR; |
| } |
| ch = loadNextChar(); |
| } |
| if (ch == -1) { |
| callCharDataHandler(offset, fCurrentOffset, false); |
| return changeReaders().scanContent(element); |
| } |
| } |
| } |
| // |
| // |
| // |
| private void callCharDataHandler(int offset, int endOffset, boolean isWhitespace) throws Exception { |
| int length = endOffset - offset; |
| if (!fSendCharDataAsCharArray) { |
| int stringIndex = addString(offset, length); |
| if (isWhitespace) |
| fCharDataHandler.processWhitespace(stringIndex); |
| else |
| fCharDataHandler.processCharacters(stringIndex); |
| return; |
| } |
| if (isWhitespace) |
| fCharDataHandler.processWhitespace(fData.toCharArray(), offset, length); |
| else |
| fCharDataHandler.processCharacters(fData.toCharArray(), offset, length); |
| } |
| // |
| // |
| // |
| private static final char[] cdata_string = { 'C','D','A','T','A','[' }; |
| // |
| // |
| // |
| private StringPool fStringPool = null; |
| private String fData = null; |
| private int fEndOffset; |
| private boolean hadTrailingSpace = false; |
| private boolean oweTrailingSpace = false; |
| private int fMostRecentChar; |
| private StringReader fNextFreeReader = null; |
| private static StringReader fgFreeReaders = null; |
| private boolean fCalledCharPropInit = false; |
| } |