0001: /*
0002: * The Apache Software License, Version 1.1
0003: *
0004: *
0005: * Copyright (c) 1999,2000 The Apache Software Foundation. All rights
0006: * reserved.
0007: *
0008: * Redistribution and use in source and binary forms, with or without
0009: * modification, are permitted provided that the following conditions
0010: * are met:
0011: *
0012: * 1. Redistributions of source code must retain the above copyright
0013: * notice, this list of conditions and the following disclaimer.
0014: *
0015: * 2. Redistributions in binary form must reproduce the above copyright
0016: * notice, this list of conditions and the following disclaimer in
0017: * the documentation and/or other materials provided with the
0018: * distribution.
0019: *
0020: * 3. The end-user documentation included with the redistribution,
0021: * if any, must include the following acknowledgment:
0022: * "This product includes software developed by the
0023: * Apache Software Foundation (http://www.apache.org/)."
0024: * Alternately, this acknowledgment may appear in the software itself,
0025: * if and wherever such third-party acknowledgments normally appear.
0026: *
0027: * 4. The names "Xerces" and "Apache Software Foundation" must
0028: * not be used to endorse or promote products derived from this
0029: * software without prior written permission. For written
0030: * permission, please contact apache@apache.org.
0031: *
0032: * 5. Products derived from this software may not be called "Apache",
0033: * nor may "Apache" appear in their name, without prior written
0034: * permission of the Apache Software Foundation.
0035: *
0036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0047: * SUCH DAMAGE.
0048: * ====================================================================
0049: *
0050: * This software consists of voluntary contributions made by many
0051: * individuals on behalf of the Apache Software Foundation and was
0052: * originally based on software copyright (c) 1999, International
0053: * Business Machines, Inc., http://www.apache.org. For more
0054: * information on the Apache Software Foundation, please see
0055: * <http://www.apache.org/>.
0056: */
0057:
0058: package org.apache.xerces.readers;
0059:
0060: import org.apache.xerces.framework.XMLErrorReporter;
0061: import org.apache.xerces.utils.CharDataChunk;
0062: import org.apache.xerces.utils.QName;
0063: import org.apache.xerces.utils.StringHasher;
0064: import org.apache.xerces.utils.StringPool;
0065: import org.apache.xerces.utils.XMLCharacterProperties;
0066: import org.apache.xerces.utils.ImplementationMessages;
0067: import org.xml.sax.SAXParseException;
0068: import java.io.Reader;
0069: import java.util.Vector;
0070:
0071: /**
0072: * An reader class for applications that need to process input data as
0073: * it arrives on the stream.
0074: *
0075: * @version $Id: StreamingCharReader.java,v 1.5 2001/02/01 09:58:22 andyc Exp $
0076: */
0077: public class StreamingCharReader extends XMLEntityReader {
0078:
0079: /**
0080: * Constructor
0081: *
0082: * @param entityHandler The entity handler.
0083: * @param errorReporter The error reporter.
0084: * @param sendCharDataAsCharArray true if char data should be reported using
0085: * char arrays instead of string handles.
0086: * @param stringPool The string pool.
0087: */
0088: public StreamingCharReader(XMLEntityHandler entityHandler,
0089: XMLErrorReporter errorReporter,
0090: boolean sendCharDataAsCharArray, Reader reader,
0091: StringPool stringPool) throws Exception {
0092: super (entityHandler, errorReporter, sendCharDataAsCharArray);
0093: fStringPool = stringPool;
0094: fCharacterStream = reader;
0095: fCurrentChunk = CharDataChunk.createChunk(fStringPool, null);
0096: loadFirstChar();
0097: }
0098:
0099: /**
0100: * Delay reporting an error message.
0101: *
0102: * If there is an error detected in the underlying input stream during
0103: * the fillCurrentChunk method, the error is described here and will be
0104: * reported when we reach that offset during normal processing. The
0105: * subclass should place a character with a value of zero at that offset,
0106: * which will be detected here as an invalid character. When the invalid
0107: * character is scanned, we will generate the deferred exception.
0108: *
0109: * @param errorCode the errorCode to report
0110: * @param args an array of arguments needed to generate a good error message
0111: * @param offset the position in the reader where the error occured
0112: */
0113: protected void deferException(int errorCode, Object[] args,
0114: int offset) {
0115: if (fDeferredErrors == null)
0116: fDeferredErrors = new Vector();
0117: DeferredError de = new DeferredError(errorCode, args, offset);
0118: fDeferredErrors.addElement(de);
0119: }
0120:
0121: /**
0122: * Change readers at end of input.
0123: *
0124: * We override our superclass method to release the final chunk
0125: * of the input data before handing off to the next reader.
0126: *
0127: * @return The next reader used to continue processing the document.
0128: */
0129: protected XMLEntityHandler.EntityReader changeReaders()
0130: throws Exception {
0131: XMLEntityHandler.EntityReader nextReader = super
0132: .changeReaders();
0133: fCurrentChunk.releaseChunk();
0134: fCurrentChunk = null;
0135: return nextReader;
0136: }
0137:
0138: //
0139: // XMLEntityHandler.EntityReader implementation
0140: //
0141: // The first five methods of the interface are implemented
0142: // in the XMLEntityHandler base class for us, namely
0143: //
0144: // public int currentOffset();
0145: // public int getLineNumber();
0146: // public int getColumnNumber();
0147: // public void setInCDSect(boolean inCDSect);
0148: // public boolean getInCDSect();
0149: //
0150:
0151: /**
0152: * Append the characters processed by this reader associated with <code>offset</code> and
0153: * <code>length</code> to the <code>CharBuffer</code>.
0154: *
0155: * @param charBuffer The <code>CharBuffer</code> to append the characters to.
0156: * @param offset The offset within this reader where the copy should start.
0157: * @param length The length within this reader where the copy should stop.
0158: */
0159: public void append(XMLEntityHandler.CharBuffer charBuffer,
0160: int offset, int length) {
0161: fCurrentChunk.append(charBuffer, offset, length);
0162: }
0163:
0164: /**
0165: * Add a string to the <code>StringPool</code> from the characters scanned using this
0166: * reader as described by <code>offset</code> and <code>length</code>.
0167: *
0168: * @param offset The offset within this reader where the characters start.
0169: * @param length The length within this reader where the characters end.
0170: * @return The <code>StringPool</code> handle for the string.
0171: */
0172: public int addString(int offset, int length) {
0173: if (length == 0)
0174: return 0;
0175: return fCurrentChunk.addString(offset, length);
0176: }
0177:
0178: /**
0179: * Add a symbol to the <code>StringPool</code> from the characters scanned using this
0180: * reader as described by <code>offset</code> and <code>length</code>.
0181: *
0182: * @param offset The offset within this reader where the characters start.
0183: * @param length The length within this reader where the characters end.
0184: * @return The <code>StringPool</code> handle for the symbol.
0185: */
0186: public int addSymbol(int offset, int length) {
0187: if (length == 0)
0188: return 0;
0189: return fCurrentChunk.addSymbol(offset, length, 0);
0190: }
0191:
0192: /**
0193: *
0194: */
0195: public boolean lookingAtChar(char chr, boolean skipPastChar)
0196: throws Exception {
0197: int ch = fMostRecentChar;
0198: if (ch != chr) {
0199: if (ch == 0) {
0200: if (atEOF(fCurrentOffset + 1)) {
0201: return changeReaders().lookingAtChar(chr,
0202: skipPastChar);
0203: }
0204: }
0205: return false;
0206: }
0207: if (skipPastChar) {
0208: fCharacterCounter++;
0209: loadNextChar();
0210: }
0211: return true;
0212: }
0213:
0214: /**
0215: *
0216: */
0217: public boolean lookingAtValidChar(boolean skipPastChar)
0218: throws Exception {
0219: int ch = fMostRecentChar;
0220: if (ch < 0xD800) {
0221: if (ch >= 0x20 || ch == 0x09) {
0222: if (skipPastChar) {
0223: fCharacterCounter++;
0224: loadNextChar();
0225: }
0226: return true;
0227: }
0228: if (ch == 0x0A) {
0229: if (skipPastChar) {
0230: fLinefeedCounter++;
0231: fCharacterCounter = 1;
0232: loadNextChar();
0233: }
0234: return true;
0235: }
0236: if (ch == 0) {
0237: if (atEOF(fCurrentOffset + 1)) {
0238: return changeReaders().lookingAtValidChar(
0239: skipPastChar);
0240: }
0241: }
0242: return false;
0243: }
0244: if (ch > 0xFFFD) {
0245: return false;
0246: }
0247: if (ch < 0xDC00) {
0248: CharDataChunk savedChunk = fCurrentChunk;
0249: int savedIndex = fCurrentIndex;
0250: int savedOffset = fCurrentOffset;
0251: ch = loadNextChar();
0252: boolean valid = (ch >= 0xDC00 && ch < 0xE000);
0253: if (!valid || !skipPastChar) {
0254: fCurrentChunk = savedChunk;
0255: fCurrentIndex = savedIndex;
0256: fCurrentOffset = savedOffset;
0257: fMostRecentData = savedChunk.toCharArray();
0258: fMostRecentChar = fMostRecentData[savedIndex] & 0xFFFF;
0259: return valid;
0260: }
0261: } else if (ch < 0xE000) {
0262: return false;
0263: }
0264: if (skipPastChar) {
0265: fCharacterCounter++;
0266: loadNextChar();
0267: }
0268: return true;
0269: }
0270:
0271: /**
0272: *
0273: */
0274: public boolean lookingAtSpace(boolean skipPastChar)
0275: throws Exception {
0276: int ch = fMostRecentChar;
0277: if (ch > 0x20)
0278: return false;
0279: if (ch == 0x20 || ch == 0x09) {
0280: if (!skipPastChar)
0281: return true;
0282: fCharacterCounter++;
0283: } else if (ch == 0x0A) {
0284: if (!skipPastChar)
0285: return true;
0286: fLinefeedCounter++;
0287: fCharacterCounter = 1;
0288: } else {
0289: if (ch == 0) { // REVISIT - should we be checking this here ?
0290: if (atEOF(fCurrentOffset + 1)) {
0291: return changeReaders().lookingAtSpace(skipPastChar);
0292: }
0293: }
0294: return false;
0295: }
0296: loadNextChar();
0297: return true;
0298: }
0299:
0300: /**
0301: *
0302: */
0303: public void skipToChar(char chr) throws Exception {
0304: //
0305: // REVISIT - this will skip invalid characters without reporting them.
0306: //
0307: int ch = fMostRecentChar;
0308: while (true) {
0309: if (ch == chr)
0310: return;
0311: if (ch == 0) {
0312: if (atEOF(fCurrentOffset + 1)) {
0313: changeReaders().skipToChar(chr);
0314: return;
0315: }
0316: fCharacterCounter++;
0317: } else if (ch == 0x0A) {
0318: fLinefeedCounter++;
0319: fCharacterCounter = 1;
0320: } else if (ch >= 0xD800 && ch < 0xDC00) {
0321: fCharacterCounter++;
0322: ch = loadNextChar();
0323: if (ch < 0xDC00 || ch >= 0xE000)
0324: continue;
0325: } else
0326: fCharacterCounter++;
0327: ch = loadNextChar();
0328: }
0329: }
0330:
0331: /**
0332: *
0333: */
0334: public void skipPastSpaces() throws Exception {
0335: int ch = fMostRecentChar;
0336: while (true) {
0337: if (ch == 0x20 || ch == 0x09) {
0338: fCharacterCounter++;
0339: } else if (ch == 0x0A) {
0340: fLinefeedCounter++;
0341: fCharacterCounter = 1;
0342: } else {
0343: if (ch == 0 && atEOF(fCurrentOffset + 1))
0344: changeReaders().skipPastSpaces();
0345: return;
0346: }
0347: ch = loadNextChar();
0348: }
0349: }
0350:
0351: /**
0352: *
0353: */
0354: public void skipPastName(char fastcheck) throws Exception {
0355: int ch = fMostRecentChar;
0356: if (ch < 0x80) {
0357: if (XMLCharacterProperties.fgAsciiInitialNameChar[ch] == 0)
0358: return;
0359: } else {
0360: if (!fCalledCharPropInit) {
0361: XMLCharacterProperties.initCharFlags();
0362: fCalledCharPropInit = true;
0363: }
0364: if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_InitialNameCharFlag) == 0)
0365: return;
0366: }
0367: while (true) {
0368: fCharacterCounter++;
0369: ch = loadNextChar();
0370: if (fastcheck == ch)
0371: return;
0372: if (ch < 0x80) {
0373: if (XMLCharacterProperties.fgAsciiNameChar[ch] == 0)
0374: return;
0375: } else {
0376: if (!fCalledCharPropInit) {
0377: XMLCharacterProperties.initCharFlags();
0378: fCalledCharPropInit = true;
0379: }
0380: if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_NameCharFlag) == 0)
0381: return;
0382: }
0383: }
0384: }
0385:
0386: /**
0387: *
0388: */
0389: public void skipPastNmtoken(char fastcheck) throws Exception {
0390: int ch = fMostRecentChar;
0391: while (true) {
0392: if (fastcheck == ch)
0393: return;
0394: if (ch < 0x80) {
0395: if (XMLCharacterProperties.fgAsciiNameChar[ch] == 0)
0396: return;
0397: } else {
0398: if (!fCalledCharPropInit) {
0399: XMLCharacterProperties.initCharFlags();
0400: fCalledCharPropInit = true;
0401: }
0402: if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_NameCharFlag) == 0)
0403: return;
0404: }
0405: fCharacterCounter++;
0406: ch = loadNextChar();
0407: }
0408: }
0409:
0410: /**
0411: *
0412: */
0413: public boolean skippedString(char[] s) throws Exception {
0414: int ch = fMostRecentChar;
0415: if (ch != s[0])
0416: return false;
0417: int length = s.length;
0418: CharDataChunk dataChunk = fCurrentChunk;
0419: int offset = fCurrentOffset;
0420: int index = fCurrentIndex;
0421: ch = loadNextChar();
0422: for (int i = 1; i < length; i++) {
0423: if (ch != s[i]) {
0424: fCurrentChunk = dataChunk;
0425: fCurrentIndex = index;
0426: fCurrentOffset = offset;
0427: fMostRecentData = dataChunk.toCharArray();
0428: fMostRecentChar = fMostRecentData[index] & 0xFFFF;
0429: return false;
0430: }
0431: ch = loadNextChar();
0432: }
0433: fCharacterCounter += length;
0434: return true;
0435: }
0436:
0437: /**
0438: *
0439: */
0440: public int scanInvalidChar() throws Exception {
0441: int ch = fMostRecentChar;
0442: if (ch == 0x0A) {
0443: fLinefeedCounter++;
0444: fCharacterCounter = 1;
0445: loadNextChar();
0446: } else if (ch == 0) {
0447: if (atEOF(fCurrentOffset + 1)) {
0448: return changeReaders().scanInvalidChar();
0449: }
0450: if (fDeferredErrors != null) {
0451: for (int i = 0; i < fDeferredErrors.size(); i++) {
0452: DeferredError de = (DeferredError) fDeferredErrors
0453: .elementAt(i);
0454: if (de.offset == fCurrentIndex) {
0455: fErrorReporter
0456: .reportError(
0457: fErrorReporter.getLocator(),
0458: ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
0459: de.errorCode,
0460: 0,
0461: de.args,
0462: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0463: fDeferredErrors.removeElementAt(i);
0464: fCharacterCounter++;
0465: loadNextChar();
0466: return -1;
0467: }
0468: }
0469: }
0470: fCharacterCounter++;
0471: loadNextChar();
0472: } else {
0473: fCharacterCounter++;
0474: if (ch >= 0xD800 && ch < 0xDC00) {
0475: int ch2 = loadNextChar();
0476: if (ch2 >= 0xDC00 && ch2 < 0xE000) {
0477: ch = ((ch - 0xD800) << 10) + (ch2 - 0xDC00)
0478: + 0x10000;
0479: loadNextChar();
0480: }
0481: } else
0482: loadNextChar();
0483: }
0484: return ch;
0485: }
0486:
0487: /**
0488: *
0489: */
0490: public int scanCharRef(boolean hex) throws Exception {
0491: int ch = fMostRecentChar;
0492: if (ch == 0) {
0493: if (atEOF(fCurrentOffset + 1)) {
0494: return changeReaders().scanCharRef(hex);
0495: }
0496: return XMLEntityHandler.CHARREF_RESULT_INVALID_CHAR;
0497: }
0498: int num = 0;
0499: if (hex) {
0500: if (ch > 'f'
0501: || XMLCharacterProperties.fgAsciiXDigitChar[ch] == 0)
0502: return XMLEntityHandler.CHARREF_RESULT_INVALID_CHAR;
0503: num = ch - (ch < 'A' ? '0' : (ch < 'a' ? 'A' : 'a') - 10);
0504: } else {
0505: if (ch < '0' || ch > '9')
0506: return XMLEntityHandler.CHARREF_RESULT_INVALID_CHAR;
0507: num = ch - '0';
0508: }
0509: fCharacterCounter++;
0510: loadNextChar();
0511: boolean toobig = false;
0512: while (true) {
0513: ch = fMostRecentChar;
0514: if (ch == 0)
0515: break;
0516: if (hex) {
0517: if (ch > 'f'
0518: || XMLCharacterProperties.fgAsciiXDigitChar[ch] == 0)
0519: break;
0520: } else {
0521: if (ch < '0' || ch > '9')
0522: break;
0523: }
0524: fCharacterCounter++;
0525: loadNextChar();
0526: if (hex) {
0527: int dig = ch
0528: - (ch < 'A' ? '0' : (ch < 'a' ? 'A' : 'a') - 10);
0529: num = (num << 4) + dig;
0530: } else {
0531: int dig = ch - '0';
0532: num = (num * 10) + dig;
0533: }
0534: if (num > 0x10FFFF) {
0535: toobig = true;
0536: num = 0;
0537: }
0538: }
0539: if (ch != ';')
0540: return XMLEntityHandler.CHARREF_RESULT_SEMICOLON_REQUIRED;
0541: fCharacterCounter++;
0542: loadNextChar();
0543: if (toobig)
0544: return XMLEntityHandler.CHARREF_RESULT_OUT_OF_RANGE;
0545: return num;
0546: }
0547:
0548: /**
0549: *
0550: */
0551: public int scanStringLiteral() throws Exception {
0552: boolean single;
0553: if (!(single = lookingAtChar('\'', true))
0554: && !lookingAtChar('\"', true)) {
0555: return XMLEntityHandler.STRINGLIT_RESULT_QUOTE_REQUIRED;
0556: }
0557: int offset = fCurrentOffset;
0558: char qchar = single ? '\'' : '\"';
0559: while (!lookingAtChar(qchar, false)) {
0560: if (!lookingAtValidChar(true)) {
0561: return XMLEntityHandler.STRINGLIT_RESULT_INVALID_CHAR;
0562: }
0563: }
0564: int stringIndex = addString(offset, fCurrentOffset - offset);
0565: lookingAtChar(qchar, true); // move past qchar
0566: return stringIndex;
0567: }
0568:
0569: //
0570: // [10] AttValue ::= '"' ([^<&"] | Reference)* '"'
0571: // | "'" ([^<&'] | Reference)* "'"
0572: //
0573: /**
0574: *
0575: */
0576: public int scanAttValue(char qchar, boolean asSymbol)
0577: throws Exception {
0578: int offset = fCurrentOffset;
0579: while (true) {
0580: if (lookingAtChar(qchar, false)) {
0581: break;
0582: }
0583: if (lookingAtChar(' ', true)) {
0584: continue;
0585: }
0586: if (lookingAtSpace(false)) {
0587: return XMLEntityHandler.ATTVALUE_RESULT_COMPLEX;
0588: }
0589: if (lookingAtChar('&', false)) {
0590: return XMLEntityHandler.ATTVALUE_RESULT_COMPLEX;
0591: }
0592: if (lookingAtChar('<', false)) {
0593: return XMLEntityHandler.ATTVALUE_RESULT_LESSTHAN;
0594: }
0595: if (!lookingAtValidChar(true)) {
0596: return XMLEntityHandler.ATTVALUE_RESULT_INVALID_CHAR;
0597: }
0598: }
0599: int result = asSymbol ? addSymbol(offset, fCurrentOffset
0600: - offset) : addString(offset, fCurrentOffset - offset);
0601: lookingAtChar(qchar, true);
0602: return result;
0603: }
0604:
0605: //
0606: // [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"'
0607: // | "'" ([^%&'] | PEReference | Reference)* "'"
0608: //
0609: /**
0610: *
0611: */
0612: public int scanEntityValue(int qchar, boolean createString)
0613: throws Exception {
0614: int offset = fCurrentOffset;
0615: while (true) {
0616: if (atEOF(fCurrentOffset + 1)) {
0617: changeReaders();
0618: return XMLEntityHandler.ENTITYVALUE_RESULT_END_OF_INPUT;
0619: }
0620: if (qchar != -1 && lookingAtChar((char) qchar, false)) {
0621: if (!createString)
0622: return XMLEntityHandler.ENTITYVALUE_RESULT_FINISHED;
0623: break;
0624: }
0625: if (lookingAtChar('&', false)) {
0626: return XMLEntityHandler.ENTITYVALUE_RESULT_REFERENCE;
0627: }
0628: if (lookingAtChar('%', false)) {
0629: return XMLEntityHandler.ENTITYVALUE_RESULT_PEREF;
0630: }
0631: if (!lookingAtValidChar(true)) {
0632: return XMLEntityHandler.ENTITYVALUE_RESULT_INVALID_CHAR;
0633: }
0634: }
0635: int result = addString(offset, fCurrentOffset - offset);
0636: lookingAtChar((char) qchar, true);
0637: return result;
0638: }
0639:
0640: /**
0641: *
0642: */
0643: public int scanName(char fastcheck) throws Exception {
0644: int ch = fMostRecentChar;
0645: if (ch < 0x80) {
0646: if (XMLCharacterProperties.fgAsciiInitialNameChar[ch] == 0)
0647: return -1;
0648: } else {
0649: if (!fCalledCharPropInit) {
0650: XMLCharacterProperties.initCharFlags();
0651: fCalledCharPropInit = true;
0652: }
0653: if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_InitialNameCharFlag) == 0)
0654: return -1;
0655: }
0656: int offset = fCurrentOffset;
0657: fCharacterCounter++;
0658: int hashcode = 0;
0659: while (true) {
0660: hashcode = StringHasher.hashChar(hashcode, ch);
0661: ch = loadNextChar();
0662: if (fastcheck == ch)
0663: break;
0664: if (ch < 0x80) {
0665: if (XMLCharacterProperties.fgAsciiNameChar[ch] == 0)
0666: break;
0667: } else {
0668: if (!fCalledCharPropInit) {
0669: XMLCharacterProperties.initCharFlags();
0670: fCalledCharPropInit = true;
0671: }
0672: if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_NameCharFlag) == 0)
0673: break;
0674: }
0675: fCharacterCounter++;
0676: }
0677: hashcode = StringHasher.finishHash(hashcode);
0678: int length = fCurrentOffset - offset;
0679: int nameIndex = fCurrentChunk.addSymbol(offset, length,
0680: hashcode);
0681: return nameIndex;
0682: }
0683:
0684: /**
0685: *
0686: */
0687: public boolean scanExpectedName(char fastcheck,
0688: StringPool.CharArrayRange expectedName) throws Exception {
0689: char[] expected = expectedName.chars;
0690: int offset = expectedName.offset;
0691: int len = expectedName.length;
0692: int ch = fMostRecentChar;
0693: for (int i = 0; i < len; i++) {
0694: if (ch != expected[offset++]) {
0695: skipPastNmtoken(fastcheck);
0696: return false;
0697: }
0698: fCharacterCounter++;
0699: ch = loadNextChar();
0700: }
0701: if (ch == fastcheck)
0702: return true;
0703: if (ch < 0x80) {
0704: if (XMLCharacterProperties.fgAsciiNameChar[ch] == 0)
0705: return true;
0706: } else {
0707: if (!fCalledCharPropInit) {
0708: XMLCharacterProperties.initCharFlags();
0709: fCalledCharPropInit = true;
0710: }
0711: if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_NameCharFlag) == 0)
0712: return true;
0713: }
0714: skipPastNmtoken(fastcheck);
0715: return false;
0716: }
0717:
0718: /**
0719: *
0720: */
0721: public void scanQName(char fastcheck, QName qname) throws Exception {
0722: int ch = fMostRecentChar;
0723: if (ch < 0x80) {
0724: if (XMLCharacterProperties.fgAsciiInitialNameChar[ch] == 0) {
0725: qname.clear();
0726: return;
0727: }
0728: if (ch == ':') {
0729: qname.clear();
0730: return;
0731: }
0732: } else {
0733: if (!fCalledCharPropInit) {
0734: XMLCharacterProperties.initCharFlags();
0735: fCalledCharPropInit = true;
0736: }
0737: if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_InitialNameCharFlag) == 0) {
0738: qname.clear();
0739: return;
0740: }
0741: }
0742: int offset = fCurrentOffset;
0743: fCharacterCounter++;
0744: int hashcode = 0;
0745: int prefixend = -1;
0746: while (true) {
0747: hashcode = StringHasher.hashChar(hashcode, ch);
0748: ch = loadNextChar();
0749: if (fastcheck == ch)
0750: break;
0751: if (ch < 0x80) {
0752: if (XMLCharacterProperties.fgAsciiNameChar[ch] == 0)
0753: break;
0754: if (ch == ':') {
0755: if (prefixend != -1)
0756: break;
0757: prefixend = fCurrentOffset;
0758: //
0759: // We need to peek ahead one character. If the next character is not a
0760: // valid initial name character, or is another colon, then we cannot meet
0761: // both the Prefix and LocalPart productions for the QName production,
0762: // which means that there is no Prefix and we need to terminate the QName
0763: // at the first colon.
0764: //
0765: CharDataChunk savedChunk = fCurrentChunk;
0766: int savedOffset = fCurrentOffset;
0767: int savedIndex = fCurrentIndex;
0768: ch = loadNextChar();
0769: fCurrentChunk = savedChunk;
0770: fCurrentOffset = savedOffset;
0771: fCurrentIndex = savedIndex;
0772: fMostRecentData = savedChunk.toCharArray();
0773: boolean lpok = true;
0774: if (ch < 0x80) {
0775: if (XMLCharacterProperties.fgAsciiInitialNameChar[ch] == 0
0776: || ch == ':')
0777: lpok = false;
0778: } else {
0779: if (!fCalledCharPropInit) {
0780: XMLCharacterProperties.initCharFlags();
0781: fCalledCharPropInit = true;
0782: }
0783: if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_InitialNameCharFlag) == 0)
0784: lpok = false;
0785: }
0786: ch = ':';
0787: if (!lpok) {
0788: prefixend = -1;
0789: fMostRecentChar = ch;
0790: break;
0791: }
0792: }
0793: } else {
0794: if (!fCalledCharPropInit) {
0795: XMLCharacterProperties.initCharFlags();
0796: fCalledCharPropInit = true;
0797: }
0798: if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_NameCharFlag) == 0)
0799: break;
0800: }
0801: fCharacterCounter++;
0802: }
0803: hashcode = StringHasher.finishHash(hashcode);
0804: int length = fCurrentOffset - offset;
0805: qname.rawname = fCurrentChunk.addSymbol(offset, length,
0806: hashcode);
0807: qname.prefix = prefixend == -1 ? -1 : addSymbol(offset,
0808: prefixend - offset);
0809: qname.localpart = prefixend == -1 ? qname.rawname : addSymbol(
0810: prefixend + 1, fCurrentOffset - (prefixend + 1));
0811: qname.uri = StringPool.EMPTY_STRING;
0812:
0813: } // scanQName(char,QName)
0814:
0815: //
0816: // [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
0817: //
0818: /**
0819: *
0820: */
0821: public int scanContent(QName element) throws Exception {
0822: if (fCallClearPreviousChunk
0823: && fCurrentChunk.clearPreviousChunk())
0824: fCallClearPreviousChunk = false;
0825: int charDataOffset = fCurrentOffset;
0826: int ch = fMostRecentChar;
0827: if (ch < 0x80) {
0828: switch (XMLCharacterProperties.fgAsciiWSCharData[ch]) {
0829: case 0:
0830: fCharacterCounter++;
0831: ch = loadNextChar();
0832: break;
0833: case 1: // '<'
0834: fCharacterCounter++;
0835: ch = loadNextChar();
0836: if (!fInCDSect) {
0837: return recognizeMarkup(ch);
0838: }
0839: break;
0840: case 2: // '&'
0841: fCharacterCounter++;
0842: ch = loadNextChar();
0843: if (!fInCDSect) {
0844: return recognizeReference(ch);
0845: }
0846: break;
0847: case 3: // ']'
0848: fCharacterCounter++;
0849: ch = loadNextChar();
0850: if (ch != ']')
0851: break;
0852: {
0853: CharDataChunk dataChunk = fCurrentChunk;
0854: int index = fCurrentIndex;
0855: int offset = fCurrentOffset;
0856: if (loadNextChar() != '>') {
0857: fCurrentChunk = dataChunk;
0858: fCurrentIndex = index;
0859: fCurrentOffset = offset;
0860: fMostRecentData = dataChunk.toCharArray();
0861: fMostRecentChar = ']';
0862: break;
0863: }
0864: }
0865: loadNextChar();
0866: fCharacterCounter += 2;
0867: return XMLEntityHandler.CONTENT_RESULT_END_OF_CDSECT;
0868: case 4: // invalid char
0869: if (ch == 0 && atEOF(fCurrentOffset + 1)) {
0870: changeReaders();
0871: return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR; // REVISIT - not quite...
0872: }
0873: return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR;
0874: case 5:
0875: do {
0876: if (ch == 0x0A) {
0877: fLinefeedCounter++;
0878: fCharacterCounter = 1;
0879: } else
0880: fCharacterCounter++;
0881: ch = loadNextChar();
0882: } while (ch == 0x20 || ch == 0x09 || ch == 0x0A);
0883: if (ch < 0x80) {
0884: switch (XMLCharacterProperties.fgAsciiCharData[ch]) {
0885: case 0:
0886: fCharacterCounter++;
0887: ch = loadNextChar();
0888: break;
0889: case 1: // '<'
0890: if (!fInCDSect) {
0891: callCharDataHandler(charDataOffset,
0892: fCurrentOffset, true);
0893: fCharacterCounter++;
0894: ch = loadNextChar();
0895: return recognizeMarkup(ch);
0896: }
0897: fCharacterCounter++;
0898: ch = loadNextChar();
0899: break;
0900: case 2: // '&'
0901: if (!fInCDSect) {
0902: callCharDataHandler(charDataOffset,
0903: fCurrentOffset, true);
0904: fCharacterCounter++;
0905: ch = loadNextChar();
0906: return recognizeReference(ch);
0907: }
0908: fCharacterCounter++;
0909: ch = loadNextChar();
0910: break;
0911: case 3: // ']'
0912: int endOffset = fCurrentOffset;
0913: ch = loadNextChar();
0914: if (ch != ']') {
0915: fCharacterCounter++;
0916: break;
0917: }
0918: {
0919: CharDataChunk dataChunk = fCurrentChunk;
0920: int index = fCurrentIndex;
0921: int offset = fCurrentOffset;
0922: if (loadNextChar() != '>') {
0923: fCurrentChunk = dataChunk;
0924: fCurrentIndex = index;
0925: fCurrentOffset = offset;
0926: fMostRecentData = dataChunk
0927: .toCharArray();
0928: fMostRecentChar = ']';
0929: fCharacterCounter++;
0930: break;
0931: }
0932: }
0933: loadNextChar();
0934: callCharDataHandler(charDataOffset, endOffset,
0935: true);
0936: fCharacterCounter += 3;
0937: return XMLEntityHandler.CONTENT_RESULT_END_OF_CDSECT;
0938: case 4: // invalid char
0939: callCharDataHandler(charDataOffset,
0940: fCurrentOffset, true);
0941: if (ch == 0 && atEOF(fCurrentOffset + 1)) {
0942: changeReaders();
0943: return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR; // REVISIT - not quite...
0944: }
0945: return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR;
0946: }
0947: } else if (!skipMultiByteCharData(ch)) {
0948: callCharDataHandler(charDataOffset, fCurrentOffset,
0949: true);
0950: return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR;
0951: }
0952: break;
0953: }
0954: } else if (!skipMultiByteCharData(ch)) {
0955: return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR;
0956: }
0957: ch = skipAsciiCharData();
0958: while (true) {
0959: if (ch < 0x80) {
0960: switch (XMLCharacterProperties.fgAsciiCharData[ch]) {
0961: case 0:
0962: fCharacterCounter++;
0963: ch = loadNextChar();
0964: break;
0965: case 1: // '<'
0966: if (!fInCDSect) {
0967: callCharDataHandler(charDataOffset,
0968: fCurrentOffset, false);
0969: fCharacterCounter++;
0970: ch = loadNextChar();
0971: return recognizeMarkup(ch);
0972: }
0973: fCharacterCounter++;
0974: ch = loadNextChar();
0975: break;
0976: case 2: // '&'
0977: if (!fInCDSect) {
0978: callCharDataHandler(charDataOffset,
0979: fCurrentOffset, false);
0980: fCharacterCounter++;
0981: ch = loadNextChar();
0982: return recognizeReference(ch);
0983: }
0984: fCharacterCounter++;
0985: ch = loadNextChar();
0986: break;
0987: case 3: // ']'
0988: int endOffset = fCurrentOffset;
0989: ch = loadNextChar();
0990: if (ch != ']') {
0991: fCharacterCounter++;
0992: break;
0993: }
0994: CharDataChunk dataChunk = fCurrentChunk;
0995: int index = fCurrentIndex;
0996: int offset = fCurrentOffset;
0997: if (loadNextChar() != '>') {
0998: fCurrentChunk = dataChunk;
0999: fCurrentIndex = index;
1000: fCurrentOffset = offset;
1001: fMostRecentData = dataChunk.toCharArray();
1002: fMostRecentChar = ']';
1003: fCharacterCounter++;
1004: break;
1005: }
1006: loadNextChar();
1007: callCharDataHandler(charDataOffset, endOffset,
1008: false);
1009: fCharacterCounter += 3;
1010: return XMLEntityHandler.CONTENT_RESULT_END_OF_CDSECT;
1011: case 4: // invalid char
1012: if (ch == 0x0A) {
1013: fLinefeedCounter++;
1014: fCharacterCounter = 1;
1015: ch = loadNextChar();
1016: break;
1017: }
1018: callCharDataHandler(charDataOffset, fCurrentOffset,
1019: false);
1020: if (ch == 0 && atEOF(fCurrentOffset + 1)) {
1021: changeReaders();
1022: return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR; // REVISIT - not quite...
1023: }
1024: return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR;
1025: }
1026: } else {
1027: if (!skipMultiByteCharData(ch)) {
1028: callCharDataHandler(charDataOffset, fCurrentOffset,
1029: false);
1030: return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR;
1031: }
1032: ch = fMostRecentChar;
1033: }
1034: }
1035: }
1036:
1037: //
1038: // Private data members
1039: //
1040: private static final char[] cdata_string = { 'C', 'D', 'A', 'T',
1041: 'A', '[' };
1042: private StringPool fStringPool = null;
1043: private boolean fCallClearPreviousChunk = true;
1044: private Vector fDeferredErrors = null;
1045:
1046: //
1047: // Private classes
1048: //
1049: private class DeferredError {
1050: int errorCode;
1051: Object[] args;
1052: int offset;
1053:
1054: DeferredError(int ec, Object[] a, int o) {
1055: errorCode = ec;
1056: args = a;
1057: offset = o;
1058: }
1059: }
1060:
1061: //
1062: // Private methods
1063: //
1064:
1065: /*
1066: * Return a result code for scanContent when the character data
1067: * ends with a less-than character.
1068: */
1069: private int recognizeMarkup(int ch) throws Exception {
1070: switch (ch) {
1071: case 0:
1072: return XMLEntityHandler.CONTENT_RESULT_MARKUP_END_OF_INPUT;
1073: case '?':
1074: fCharacterCounter++;
1075: loadNextChar();
1076: return XMLEntityHandler.CONTENT_RESULT_START_OF_PI;
1077: case '!':
1078: fCharacterCounter++;
1079: ch = loadNextChar();
1080: if (ch == 0) {
1081: fCharacterCounter--;
1082: fCurrentOffset--;
1083: return XMLEntityHandler.CONTENT_RESULT_MARKUP_END_OF_INPUT;
1084: }
1085: if (ch == '-') {
1086: fCharacterCounter++;
1087: ch = loadNextChar();
1088: if (ch == 0) {
1089: fCharacterCounter -= 2;
1090: fCurrentOffset -= 2;
1091: return XMLEntityHandler.CONTENT_RESULT_MARKUP_END_OF_INPUT;
1092: }
1093: if (ch == '-') {
1094: fCharacterCounter++;
1095: loadNextChar();
1096: return XMLEntityHandler.CONTENT_RESULT_START_OF_COMMENT;
1097: }
1098: break;
1099: }
1100: if (ch == '[') {
1101: for (int i = 0; i < 6; i++) {
1102: fCharacterCounter++;
1103: ch = loadNextChar();
1104: if (ch == 0) {
1105: fCharacterCounter -= (2 + i);
1106: fCurrentOffset -= (2 + i);
1107: return XMLEntityHandler.CONTENT_RESULT_MARKUP_END_OF_INPUT;
1108: }
1109: if (ch != cdata_string[i]) {
1110: return XMLEntityHandler.CONTENT_RESULT_MARKUP_NOT_RECOGNIZED;
1111: }
1112: }
1113: fCharacterCounter++;
1114: loadNextChar();
1115: return XMLEntityHandler.CONTENT_RESULT_START_OF_CDSECT;
1116: }
1117: break;
1118: case '/':
1119: fCharacterCounter++;
1120: loadNextChar();
1121: return XMLEntityHandler.CONTENT_RESULT_START_OF_ETAG;
1122: default:
1123: return XMLEntityHandler.CONTENT_RESULT_START_OF_ELEMENT;
1124: }
1125: return XMLEntityHandler.CONTENT_RESULT_MARKUP_NOT_RECOGNIZED;
1126: }
1127:
1128: /*
1129: * Return a result code for scanContent when the character data
1130: * ends with an ampersand character.
1131: */
1132: private int recognizeReference(int ch) throws Exception {
1133: if (ch == 0) {
1134: return XMLEntityHandler.CONTENT_RESULT_REFERENCE_END_OF_INPUT;
1135: }
1136: //
1137: // [67] Reference ::= EntityRef | CharRef
1138: // [68] EntityRef ::= '&' Name ';'
1139: // [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
1140: //
1141: if (ch == '#') {
1142: fCharacterCounter++;
1143: loadNextChar();
1144: return XMLEntityHandler.CONTENT_RESULT_START_OF_CHARREF;
1145: } else {
1146: return XMLEntityHandler.CONTENT_RESULT_START_OF_ENTITYREF;
1147: }
1148: }
1149:
1150: /*
1151: * Skip over a multi-byte character.
1152: */
1153: private boolean skipMultiByteCharData(int ch) throws Exception {
1154: if (ch < 0xD800) {
1155: loadNextChar();
1156: return true;
1157: }
1158: if (ch > 0xFFFD)
1159: return false;
1160: if (ch >= 0xDC00 && ch < 0xE000)
1161: return false;
1162: if (ch >= 0xD800 && ch < 0xDC00) {
1163: CharDataChunk savedChunk = fCurrentChunk;
1164: int savedIndex = fCurrentIndex;
1165: int savedOffset = fCurrentOffset;
1166: ch = loadNextChar();
1167: if (ch < 0xDC00 || ch >= 0xE000) {
1168: fCurrentChunk = savedChunk;
1169: fCurrentIndex = savedIndex;
1170: fCurrentOffset = savedOffset;
1171: fMostRecentData = savedChunk.toCharArray();
1172: fMostRecentChar = fMostRecentData[savedIndex] & 0xFFFF;
1173: return false;
1174: }
1175: }
1176: loadNextChar();
1177: return true;
1178: }
1179:
1180: /*
1181: * Skip over contiguous ascii character data.
1182: *
1183: * @return the character skipped
1184: * @exception java.lang.Exception
1185: */
1186: private int skipAsciiCharData() throws Exception {
1187: int ch = fMostRecentChar;
1188: while (true) {
1189: if (ch >= 0x80) {
1190: return ch;
1191: }
1192: if (XMLCharacterProperties.fgAsciiCharData[ch] == 0) {
1193: fCharacterCounter++;
1194: } else if (ch == 0x0A) {
1195: fLinefeedCounter++;
1196: fCharacterCounter = 1;
1197: } else {
1198: return ch;
1199: }
1200: ch = loadNextChar();
1201: }
1202: }
1203:
1204: /*
1205: * Report character data to the parser through the entity handler interface.
1206: *
1207: * @param offset the offset of the start of the character data
1208: * @param endOffset the offset of the end of the character data
1209: * @param isWhitespace true if the character data is whitespace
1210: * @exception java.lang.Exception
1211: */
1212: private void callCharDataHandler(int offset, int endOffset,
1213: boolean isWhitespace) throws Exception {
1214:
1215: int length = endOffset - offset;
1216: if (!fSendCharDataAsCharArray) {
1217: int stringIndex = addString(offset, length);
1218: if (isWhitespace)
1219: fCharDataHandler.processWhitespace(stringIndex);
1220: else
1221: fCharDataHandler.processCharacters(stringIndex);
1222: return;
1223: }
1224:
1225: CharDataChunk dataChunk = fCurrentChunk.chunkFor(offset);
1226: int index = offset & CharDataChunk.CHUNK_MASK;
1227: if (index + length <= CharDataChunk.CHUNK_SIZE) {
1228: //
1229: // All the chars are in the same chunk
1230: //
1231: if (length != 0) {
1232: if (isWhitespace)
1233: fCharDataHandler.processWhitespace(dataChunk
1234: .toCharArray(), index, length);
1235: else
1236: fCharDataHandler.processCharacters(dataChunk
1237: .toCharArray(), index, length);
1238: }
1239: return;
1240: }
1241:
1242: //
1243: // The data is spread across chunks.
1244: //
1245: int count = length;
1246: int nbytes = CharDataChunk.CHUNK_SIZE - index;
1247: if (isWhitespace)
1248: fCharDataHandler.processWhitespace(dataChunk.toCharArray(),
1249: index, nbytes);
1250: else
1251: fCharDataHandler.processCharacters(dataChunk.toCharArray(),
1252: index, nbytes);
1253: count -= nbytes;
1254:
1255: //
1256: // Use each Chunk in turn until we are done.
1257: //
1258: do {
1259: dataChunk = dataChunk.nextChunk();
1260: if (dataChunk == null) {
1261: throw new RuntimeException(
1262: new ImplementationMessages().createMessage(
1263: null, ImplementationMessages.INT_DCN,
1264: 0, null));
1265: }
1266: nbytes = count <= CharDataChunk.CHUNK_SIZE ? count
1267: : CharDataChunk.CHUNK_SIZE;
1268: if (isWhitespace)
1269: fCharDataHandler.processWhitespace(dataChunk
1270: .toCharArray(), 0, nbytes);
1271: else
1272: fCharDataHandler.processCharacters(dataChunk
1273: .toCharArray(), 0, nbytes);
1274: count -= nbytes;
1275: } while (count > 0);
1276: }
1277:
1278: /*
1279: * Advance the reader's notion of where it is, moving on to the next chunk.
1280: *
1281: * @return The next character that will be processed.
1282: * @exception java.lang.Exception
1283: */
1284: private int slowLoadNextChar() throws Exception {
1285: fCallClearPreviousChunk = true;
1286: if (fCurrentChunk.nextChunk() != null) {
1287: fCurrentChunk = fCurrentChunk.nextChunk();
1288: fCurrentIndex = 0;
1289: fMostRecentData = fCurrentChunk.toCharArray();
1290: return (fMostRecentChar = fMostRecentData[fCurrentIndex] & 0xFFFF);
1291: } else {
1292: fCurrentChunk = CharDataChunk.createChunk(fStringPool,
1293: fCurrentChunk);
1294: fCurrentIndex = 0;
1295: fFillIndex = 0;
1296: loadFirstChar();
1297: return fMostRecentChar;
1298: }
1299: }
1300:
1301: /*
1302: * Advance the reader's notion of where it is
1303: *
1304: * @return The next character that will be processed.
1305: * @exception java.lang.Exception
1306: */
1307: private int loadNextChar() throws Exception {
1308: fCurrentOffset++;
1309: if (++fCurrentIndex == CharDataChunk.CHUNK_SIZE)
1310: return slowLoadNextChar();
1311: if (fCurrentIndex < fFillIndex)
1312: return (fMostRecentChar = fMostRecentData[fCurrentIndex] & 0xFFFF);
1313: return loadMoreChars();
1314: }
1315:
1316: /*
1317: * Read the first character.
1318: *
1319: * @exception java.lang.Exception
1320: */
1321: private void loadFirstChar() throws Exception {
1322: fMostRecentData = fCurrentChunk.toCharArray();
1323: if (fMostRecentData == null) {
1324: fMostRecentData = new char[CharDataChunk.CHUNK_SIZE];
1325: fCurrentChunk.setCharArray(fMostRecentData);
1326: }
1327: loadMoreChars();
1328: }
1329:
1330: /*
1331: * Fetch more characters.
1332: *
1333: * @exception java.lang.Exception
1334: */
1335: private boolean seenCR = false;
1336: private int oweChar = -1;
1337: private char[] inBuffer = new char[2];
1338:
1339: private int loadMoreChars() throws Exception {
1340: if (oweChar != -1) {
1341: fMostRecentData[fFillIndex] = (char) oweChar;
1342: fFillIndex++;
1343: fLength++;
1344: fMostRecentChar = oweChar;
1345: oweChar = -1;
1346: return fMostRecentChar;
1347: }
1348: int result = -1;
1349: try {
1350: while (true) {
1351: result = fCharacterStream.read(inBuffer, 0, 2);
1352: switch (result) {
1353: case -1:
1354: break;
1355: case 0:
1356: continue;
1357: case 1:
1358: result = inBuffer[0];
1359: if (seenCR) {
1360: seenCR = false;
1361: if (result == 0x0A)
1362: continue;
1363: }
1364: if (result == 0x0D) {
1365: seenCR = true;
1366: result = 0x0A;
1367: }
1368: fMostRecentChar = (fMostRecentData[fFillIndex] = (char) result);
1369: fFillIndex++;
1370: fLength++;
1371: return fMostRecentChar;
1372: case 2:
1373: result = inBuffer[0];
1374: boolean readchar2 = false;
1375: if (seenCR) {
1376: seenCR = false;
1377: if (result == 0x0A) {
1378: result = inBuffer[1];
1379: readchar2 = true;
1380: }
1381: }
1382: if (result == 0x0D) {
1383: seenCR = true;
1384: result = 0x0A;
1385: }
1386: fMostRecentChar = (fMostRecentData[fFillIndex] = (char) result);
1387: fFillIndex++;
1388: fLength++;
1389: if (!readchar2) {
1390: result = inBuffer[1];
1391: if (seenCR) {
1392: seenCR = false;
1393: if (result == 0x0A)
1394: return fMostRecentChar;
1395: }
1396: if (result == 0x0D) {
1397: seenCR = true;
1398: result = 0x0A;
1399: }
1400: oweChar = result;
1401: }
1402: return fMostRecentChar;
1403: }
1404: break;
1405: }
1406: } catch (java.io.IOException ex) {
1407: }
1408: //
1409: // We have reached the end of the stream.
1410: //
1411: try {
1412: fCharacterStream.close();
1413: } catch (java.io.IOException ex) {
1414: }
1415: fCharacterStream = null;
1416: fMostRecentChar = (fMostRecentData[fFillIndex] = 0);
1417: return 0;
1418: }
1419:
1420: /*
1421: * Would the reader be at end of file at a given offset?
1422: *
1423: * @param offset the offset to test for being at EOF
1424: * @return true if being at offset would mean being at or beyond EOF
1425: */
1426: private boolean atEOF(int offset) {
1427: return (offset > fLength);
1428: }
1429:
1430: //
1431: //
1432: //
1433: protected Reader fCharacterStream = null;
1434: protected CharDataChunk fCurrentChunk = null;
1435: protected int fCurrentIndex = 0;
1436: protected int fFillIndex = 0;
1437: protected char[] fMostRecentData = null;
1438: protected int fMostRecentChar = 0;
1439: protected int fLength = 0;
1440: protected boolean fCalledCharPropInit = false;
1441:
1442: }
|