You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by mu...@apache.org on 2009/08/04 01:16:53 UTC
svn commit: r800614 [22/24] - in
/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2:
./ jasper/ jasper/compiler/ jasper/compiler/tagplugin/ jasper/resources/
jasper/runtime/ jasper/security/ jasper/servlet/ jasper/tagplugins/ jas...
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/xmlparser/UCSReader.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/xmlparser/UCSReader.java?rev=800614&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/xmlparser/UCSReader.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/xmlparser/UCSReader.java Mon Aug 3 23:16:50 2009
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.struts2.jasper.xmlparser;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * Reader for UCS-2 and UCS-4 encodings.
+ * (i.e., encodings from ISO-10646-UCS-(2|4)).
+ *
+ * @author Neil Graham, IBM
+ *
+ * @version $Id: UCSReader.java 466606 2006-10-21 23:07:12Z markt $
+ */
+public class UCSReader extends Reader {
+
+ private org.apache.commons.logging.Log log=
+ org.apache.commons.logging.LogFactory.getLog( UCSReader.class );
+
+ //
+ // Constants
+ //
+
+ /** Default byte buffer size (8192, larger than that of ASCIIReader
+ * since it's reasonable to surmise that the average UCS-4-encoded
+ * file should be 4 times as large as the average ASCII-encoded file).
+ */
+ public static final int DEFAULT_BUFFER_SIZE = 8192;
+
+ public static final short UCS2LE = 1;
+ public static final short UCS2BE = 2;
+ public static final short UCS4LE = 4;
+ public static final short UCS4BE = 8;
+
+ //
+ // Data
+ //
+
+ /** Input stream. */
+ protected InputStream fInputStream;
+
+ /** Byte buffer. */
+ protected byte[] fBuffer;
+
+ // what kind of data we're dealing with
+ protected short fEncoding;
+
+ //
+ // Constructors
+ //
+
+ /**
+ * Constructs an ASCII reader from the specified input stream
+ * using the default buffer size. The Endian-ness and whether this is
+ * UCS-2 or UCS-4 needs also to be known in advance.
+ *
+ * @param inputStream The input stream.
+ * @param encoding One of UCS2LE, UCS2BE, UCS4LE or UCS4BE.
+ */
+ public UCSReader(InputStream inputStream, short encoding) {
+ this(inputStream, DEFAULT_BUFFER_SIZE, encoding);
+ } // <init>(InputStream, short)
+
+ /**
+ * Constructs an ASCII reader from the specified input stream
+ * and buffer size. The Endian-ness and whether this is
+ * UCS-2 or UCS-4 needs also to be known in advance.
+ *
+ * @param inputStream The input stream.
+ * @param size The initial buffer size.
+ * @param encoding One of UCS2LE, UCS2BE, UCS4LE or UCS4BE.
+ */
+ public UCSReader(InputStream inputStream, int size, short encoding) {
+ fInputStream = inputStream;
+ fBuffer = new byte[size];
+ fEncoding = encoding;
+ } // <init>(InputStream,int,short)
+
+ //
+ // Reader methods
+ //
+
+ /**
+ * Read a single character. This method will block until a character is
+ * available, an I/O error occurs, or the end of the stream is reached.
+ *
+ * <p> Subclasses that intend to support efficient single-character input
+ * should override this method.
+ *
+ * @return The character read, as an integer in the range 0 to 127
+ * (<tt>0x00-0x7f</tt>), or -1 if the end of the stream has
+ * been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read() throws IOException {
+ int b0 = fInputStream.read() & 0xff;
+ if (b0 == 0xff)
+ return -1;
+ int b1 = fInputStream.read() & 0xff;
+ if (b1 == 0xff)
+ return -1;
+ if(fEncoding >=4) {
+ int b2 = fInputStream.read() & 0xff;
+ if (b2 == 0xff)
+ return -1;
+ int b3 = fInputStream.read() & 0xff;
+ if (b3 == 0xff)
+ return -1;
+ if (log.isDebugEnabled())
+ log.debug("b0 is " + (b0 & 0xff) + " b1 " + (b1 & 0xff) + " b2 " + (b2 & 0xff) + " b3 " + (b3 & 0xff));
+ if (fEncoding == UCS4BE)
+ return (b0<<24)+(b1<<16)+(b2<<8)+b3;
+ else
+ return (b3<<24)+(b2<<16)+(b1<<8)+b0;
+ } else { // UCS-2
+ if (fEncoding == UCS2BE)
+ return (b0<<8)+b1;
+ else
+ return (b1<<8)+b0;
+ }
+ } // read():int
+
+ /**
+ * Read characters into a portion of an array. This method will block
+ * until some input is available, an I/O error occurs, or the end of the
+ * stream is reached.
+ *
+ * @param ch Destination buffer
+ * @param offset Offset at which to start storing characters
+ * @param length Maximum number of characters to read
+ *
+ * @return The number of characters read, or -1 if the end of the
+ * stream has been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read(char ch[], int offset, int length) throws IOException {
+ int byteLength = length << ((fEncoding >= 4)?2:1);
+ if (byteLength > fBuffer.length) {
+ byteLength = fBuffer.length;
+ }
+ int count = fInputStream.read(fBuffer, 0, byteLength);
+ if(count == -1) return -1;
+ // try and make count be a multiple of the number of bytes we're looking for
+ if(fEncoding >= 4) { // BigEndian
+ // this looks ugly, but it avoids an if at any rate...
+ int numToRead = (4 - (count & 3) & 3);
+ for(int i=0; i<numToRead; i++) {
+ int charRead = fInputStream.read();
+ if(charRead == -1) { // end of input; something likely went wrong!A Pad buffer with nulls.
+ for (int j = i;j<numToRead; j++)
+ fBuffer[count+j] = 0;
+ break;
+ } else {
+ fBuffer[count+i] = (byte)charRead;
+ }
+ }
+ count += numToRead;
+ } else {
+ int numToRead = count & 1;
+ if(numToRead != 0) {
+ count++;
+ int charRead = fInputStream.read();
+ if(charRead == -1) { // end of input; something likely went wrong!A Pad buffer with nulls.
+ fBuffer[count] = 0;
+ } else {
+ fBuffer[count] = (byte)charRead;
+ }
+ }
+ }
+
+ // now count is a multiple of the right number of bytes
+ int numChars = count >> ((fEncoding >= 4)?2:1);
+ int curPos = 0;
+ for (int i = 0; i < numChars; i++) {
+ int b0 = fBuffer[curPos++] & 0xff;
+ int b1 = fBuffer[curPos++] & 0xff;
+ if(fEncoding >=4) {
+ int b2 = fBuffer[curPos++] & 0xff;
+ int b3 = fBuffer[curPos++] & 0xff;
+ if (fEncoding == UCS4BE)
+ ch[offset+i] = (char)((b0<<24)+(b1<<16)+(b2<<8)+b3);
+ else
+ ch[offset+i] = (char)((b3<<24)+(b2<<16)+(b1<<8)+b0);
+ } else { // UCS-2
+ if (fEncoding == UCS2BE)
+ ch[offset+i] = (char)((b0<<8)+b1);
+ else
+ ch[offset+i] = (char)((b1<<8)+b0);
+ }
+ }
+ return numChars;
+ } // read(char[],int,int)
+
+ /**
+ * Skip characters. This method will block until some characters are
+ * available, an I/O error occurs, or the end of the stream is reached.
+ *
+ * @param n The number of characters to skip
+ *
+ * @return The number of characters actually skipped
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public long skip(long n) throws IOException {
+ // charWidth will represent the number of bits to move
+ // n leftward to get num of bytes to skip, and then move the result rightward
+ // to get num of chars effectively skipped.
+ // The trick with &'ing, as with elsewhere in this dcode, is
+ // intended to avoid an expensive use of / that might not be optimized
+ // away.
+ int charWidth = (fEncoding >=4)?2:1;
+ long bytesSkipped = fInputStream.skip(n<<charWidth);
+ if((bytesSkipped & (charWidth | 1)) == 0) return bytesSkipped >> charWidth;
+ return (bytesSkipped >> charWidth) + 1;
+ } // skip(long):long
+
+ /**
+ * Tell whether this stream is ready to be read.
+ *
+ * @return True if the next read() is guaranteed not to block for input,
+ * false otherwise. Note that returning false does not guarantee that the
+ * next read will block.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public boolean ready() throws IOException {
+ return false;
+ } // ready()
+
+ /**
+ * Tell whether this stream supports the mark() operation.
+ */
+ public boolean markSupported() {
+ return fInputStream.markSupported();
+ } // markSupported()
+
+ /**
+ * Mark the present position in the stream. Subsequent calls to reset()
+ * will attempt to reposition the stream to this point. Not all
+ * character-input streams support the mark() operation.
+ *
+ * @param readAheadLimit Limit on the number of characters that may be
+ * read while still preserving the mark. After
+ * reading this many characters, attempting to
+ * reset the stream may fail.
+ *
+ * @exception IOException If the stream does not support mark(),
+ * or if some other I/O error occurs
+ */
+ public void mark(int readAheadLimit) throws IOException {
+ fInputStream.mark(readAheadLimit);
+ } // mark(int)
+
+ /**
+ * Reset the stream. If the stream has been marked, then attempt to
+ * reposition it at the mark. If the stream has not been marked, then
+ * attempt to reset it in some way appropriate to the particular stream,
+ * for example by repositioning it to its starting point. Not all
+ * character-input streams support the reset() operation, and some support
+ * reset() without supporting mark().
+ *
+ * @exception IOException If the stream has not been marked,
+ * or if the mark has been invalidated,
+ * or if the stream does not support reset(),
+ * or if some other I/O error occurs
+ */
+ public void reset() throws IOException {
+ fInputStream.reset();
+ } // reset()
+
+ /**
+ * Close the stream. Once a stream has been closed, further read(),
+ * ready(), mark(), or reset() invocations will throw an IOException.
+ * Closing a previously-closed stream, however, has no effect.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void close() throws IOException {
+ fInputStream.close();
+ } // close()
+
+} // class UCSReader
Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/xmlparser/UTF8Reader.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/xmlparser/UTF8Reader.java?rev=800614&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/xmlparser/UTF8Reader.java (added)
+++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts2/jasper/xmlparser/UTF8Reader.java Mon Aug 3 23:16:50 2009
@@ -0,0 +1,635 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.struts2.jasper.xmlparser;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.UTFDataFormatException;
+import org.apache.struts2.jasper.compiler.Localizer;
+
+/**
+ * @author Andy Clark, IBM
+ *
+ * @version $Id: UTF8Reader.java 466606 2006-10-21 23:07:12Z markt $
+ */
+public class UTF8Reader
+ extends Reader {
+
+ private org.apache.commons.logging.Log log=
+ org.apache.commons.logging.LogFactory.getLog( UTF8Reader.class );
+
+ //
+ // Constants
+ //
+
+ /** Default byte buffer size (2048). */
+ public static final int DEFAULT_BUFFER_SIZE = 2048;
+
+ // debugging
+
+ /** Debug read. */
+ private static final boolean DEBUG_READ = false;
+
+ //
+ // Data
+ //
+
+ /** Input stream. */
+ protected InputStream fInputStream;
+
+ /** Byte buffer. */
+ protected byte[] fBuffer;
+
+ /** Offset into buffer. */
+ protected int fOffset;
+
+ /** Surrogate character. */
+ private int fSurrogate = -1;
+
+ //
+ // Constructors
+ //
+
+ /**
+ * Constructs a UTF-8 reader from the specified input stream,
+ * buffer size and MessageFormatter.
+ *
+ * @param inputStream The input stream.
+ * @param size The initial buffer size.
+ */
+ public UTF8Reader(InputStream inputStream, int size) {
+ fInputStream = inputStream;
+ fBuffer = new byte[size];
+ }
+
+ //
+ // Reader methods
+ //
+
+ /**
+ * Read a single character. This method will block until a character is
+ * available, an I/O error occurs, or the end of the stream is reached.
+ *
+ * <p> Subclasses that intend to support efficient single-character input
+ * should override this method.
+ *
+ * @return The character read, as an integer in the range 0 to 16383
+ * (<tt>0x00-0xffff</tt>), or -1 if the end of the stream has
+ * been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read() throws IOException {
+
+ // decode character
+ int c = fSurrogate;
+ if (fSurrogate == -1) {
+ // NOTE: We use the index into the buffer if there are remaining
+ // bytes from the last block read. -Ac
+ int index = 0;
+
+ // get first byte
+ int b0 = index == fOffset
+ ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+ if (b0 == -1) {
+ return -1;
+ }
+
+ // UTF-8: [0xxx xxxx]
+ // Unicode: [0000 0000] [0xxx xxxx]
+ if (b0 < 0x80) {
+ c = (char)b0;
+ }
+
+ // UTF-8: [110y yyyy] [10xx xxxx]
+ // Unicode: [0000 0yyy] [yyxx xxxx]
+ else if ((b0 & 0xE0) == 0xC0) {
+ int b1 = index == fOffset
+ ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+ if (b1 == -1) {
+ expectedByte(2, 2);
+ }
+ if ((b1 & 0xC0) != 0x80) {
+ invalidByte(2, 2, b1);
+ }
+ c = ((b0 << 6) & 0x07C0) | (b1 & 0x003F);
+ }
+
+ // UTF-8: [1110 zzzz] [10yy yyyy] [10xx xxxx]
+ // Unicode: [zzzz yyyy] [yyxx xxxx]
+ else if ((b0 & 0xF0) == 0xE0) {
+ int b1 = index == fOffset
+ ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+ if (b1 == -1) {
+ expectedByte(2, 3);
+ }
+ if ((b1 & 0xC0) != 0x80) {
+ invalidByte(2, 3, b1);
+ }
+ int b2 = index == fOffset
+ ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+ if (b2 == -1) {
+ expectedByte(3, 3);
+ }
+ if ((b2 & 0xC0) != 0x80) {
+ invalidByte(3, 3, b2);
+ }
+ c = ((b0 << 12) & 0xF000) | ((b1 << 6) & 0x0FC0) |
+ (b2 & 0x003F);
+ }
+
+ // UTF-8: [1111 0uuu] [10uu zzzz] [10yy yyyy] [10xx xxxx]*
+ // Unicode: [1101 10ww] [wwzz zzyy] (high surrogate)
+ // [1101 11yy] [yyxx xxxx] (low surrogate)
+ // * uuuuu = wwww + 1
+ else if ((b0 & 0xF8) == 0xF0) {
+ int b1 = index == fOffset
+ ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+ if (b1 == -1) {
+ expectedByte(2, 4);
+ }
+ if ((b1 & 0xC0) != 0x80) {
+ invalidByte(2, 3, b1);
+ }
+ int b2 = index == fOffset
+ ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+ if (b2 == -1) {
+ expectedByte(3, 4);
+ }
+ if ((b2 & 0xC0) != 0x80) {
+ invalidByte(3, 3, b2);
+ }
+ int b3 = index == fOffset
+ ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+ if (b3 == -1) {
+ expectedByte(4, 4);
+ }
+ if ((b3 & 0xC0) != 0x80) {
+ invalidByte(4, 4, b3);
+ }
+ int uuuuu = ((b0 << 2) & 0x001C) | ((b1 >> 4) & 0x0003);
+ if (uuuuu > 0x10) {
+ invalidSurrogate(uuuuu);
+ }
+ int wwww = uuuuu - 1;
+ int hs = 0xD800 |
+ ((wwww << 6) & 0x03C0) | ((b1 << 2) & 0x003C) |
+ ((b2 >> 4) & 0x0003);
+ int ls = 0xDC00 | ((b2 << 6) & 0x03C0) | (b3 & 0x003F);
+ c = hs;
+ fSurrogate = ls;
+ }
+
+ // error
+ else {
+ invalidByte(1, 1, b0);
+ }
+ }
+
+ // use surrogate
+ else {
+ fSurrogate = -1;
+ }
+
+ // return character
+ if (DEBUG_READ) {
+ if (log.isDebugEnabled())
+ log.debug("read(): 0x"+Integer.toHexString(c));
+ }
+ return c;
+
+ } // read():int
+
+ /**
+ * Read characters into a portion of an array. This method will block
+ * until some input is available, an I/O error occurs, or the end of the
+ * stream is reached.
+ *
+ * @param ch Destination buffer
+ * @param offset Offset at which to start storing characters
+ * @param length Maximum number of characters to read
+ *
+ * @return The number of characters read, or -1 if the end of the
+ * stream has been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read(char ch[], int offset, int length) throws IOException {
+
+ // handle surrogate
+ int out = offset;
+ if (fSurrogate != -1) {
+ ch[offset + 1] = (char)fSurrogate;
+ fSurrogate = -1;
+ length--;
+ out++;
+ }
+
+ // read bytes
+ int count = 0;
+ if (fOffset == 0) {
+ // adjust length to read
+ if (length > fBuffer.length) {
+ length = fBuffer.length;
+ }
+
+ // perform read operation
+ count = fInputStream.read(fBuffer, 0, length);
+ if (count == -1) {
+ return -1;
+ }
+ count += out - offset;
+ }
+
+ // skip read; last character was in error
+ // NOTE: Having an offset value other than zero means that there was
+ // an error in the last character read. In this case, we have
+ // skipped the read so we don't consume any bytes past the
+ // error. By signalling the error on the next block read we
+ // allow the method to return the most valid characters that
+ // it can on the previous block read. -Ac
+ else {
+ count = fOffset;
+ fOffset = 0;
+ }
+
+ // convert bytes to characters
+ final int total = count;
+ for (int in = 0; in < total; in++) {
+ int b0 = fBuffer[in] & 0x00FF;
+
+ // UTF-8: [0xxx xxxx]
+ // Unicode: [0000 0000] [0xxx xxxx]
+ if (b0 < 0x80) {
+ ch[out++] = (char)b0;
+ continue;
+ }
+
+ // UTF-8: [110y yyyy] [10xx xxxx]
+ // Unicode: [0000 0yyy] [yyxx xxxx]
+ if ((b0 & 0xE0) == 0xC0) {
+ int b1 = -1;
+ if (++in < total) {
+ b1 = fBuffer[in] & 0x00FF;
+ }
+ else {
+ b1 = fInputStream.read();
+ if (b1 == -1) {
+ if (out > offset) {
+ fBuffer[0] = (byte)b0;
+ fOffset = 1;
+ return out - offset;
+ }
+ expectedByte(2, 2);
+ }
+ count++;
+ }
+ if ((b1 & 0xC0) != 0x80) {
+ if (out > offset) {
+ fBuffer[0] = (byte)b0;
+ fBuffer[1] = (byte)b1;
+ fOffset = 2;
+ return out - offset;
+ }
+ invalidByte(2, 2, b1);
+ }
+ int c = ((b0 << 6) & 0x07C0) | (b1 & 0x003F);
+ ch[out++] = (char)c;
+ count -= 1;
+ continue;
+ }
+
+ // UTF-8: [1110 zzzz] [10yy yyyy] [10xx xxxx]
+ // Unicode: [zzzz yyyy] [yyxx xxxx]
+ if ((b0 & 0xF0) == 0xE0) {
+ int b1 = -1;
+ if (++in < total) {
+ b1 = fBuffer[in] & 0x00FF;
+ }
+ else {
+ b1 = fInputStream.read();
+ if (b1 == -1) {
+ if (out > offset) {
+ fBuffer[0] = (byte)b0;
+ fOffset = 1;
+ return out - offset;
+ }
+ expectedByte(2, 3);
+ }
+ count++;
+ }
+ if ((b1 & 0xC0) != 0x80) {
+ if (out > offset) {
+ fBuffer[0] = (byte)b0;
+ fBuffer[1] = (byte)b1;
+ fOffset = 2;
+ return out - offset;
+ }
+ invalidByte(2, 3, b1);
+ }
+ int b2 = -1;
+ if (++in < total) {
+ b2 = fBuffer[in] & 0x00FF;
+ }
+ else {
+ b2 = fInputStream.read();
+ if (b2 == -1) {
+ if (out > offset) {
+ fBuffer[0] = (byte)b0;
+ fBuffer[1] = (byte)b1;
+ fOffset = 2;
+ return out - offset;
+ }
+ expectedByte(3, 3);
+ }
+ count++;
+ }
+ if ((b2 & 0xC0) != 0x80) {
+ if (out > offset) {
+ fBuffer[0] = (byte)b0;
+ fBuffer[1] = (byte)b1;
+ fBuffer[2] = (byte)b2;
+ fOffset = 3;
+ return out - offset;
+ }
+ invalidByte(3, 3, b2);
+ }
+ int c = ((b0 << 12) & 0xF000) | ((b1 << 6) & 0x0FC0) |
+ (b2 & 0x003F);
+ ch[out++] = (char)c;
+ count -= 2;
+ continue;
+ }
+
+ // UTF-8: [1111 0uuu] [10uu zzzz] [10yy yyyy] [10xx xxxx]*
+ // Unicode: [1101 10ww] [wwzz zzyy] (high surrogate)
+ // [1101 11yy] [yyxx xxxx] (low surrogate)
+ // * uuuuu = wwww + 1
+ if ((b0 & 0xF8) == 0xF0) {
+ int b1 = -1;
+ if (++in < total) {
+ b1 = fBuffer[in] & 0x00FF;
+ }
+ else {
+ b1 = fInputStream.read();
+ if (b1 == -1) {
+ if (out > offset) {
+ fBuffer[0] = (byte)b0;
+ fOffset = 1;
+ return out - offset;
+ }
+ expectedByte(2, 4);
+ }
+ count++;
+ }
+ if ((b1 & 0xC0) != 0x80) {
+ if (out > offset) {
+ fBuffer[0] = (byte)b0;
+ fBuffer[1] = (byte)b1;
+ fOffset = 2;
+ return out - offset;
+ }
+ invalidByte(2, 4, b1);
+ }
+ int b2 = -1;
+ if (++in < total) {
+ b2 = fBuffer[in] & 0x00FF;
+ }
+ else {
+ b2 = fInputStream.read();
+ if (b2 == -1) {
+ if (out > offset) {
+ fBuffer[0] = (byte)b0;
+ fBuffer[1] = (byte)b1;
+ fOffset = 2;
+ return out - offset;
+ }
+ expectedByte(3, 4);
+ }
+ count++;
+ }
+ if ((b2 & 0xC0) != 0x80) {
+ if (out > offset) {
+ fBuffer[0] = (byte)b0;
+ fBuffer[1] = (byte)b1;
+ fBuffer[2] = (byte)b2;
+ fOffset = 3;
+ return out - offset;
+ }
+ invalidByte(3, 4, b2);
+ }
+ int b3 = -1;
+ if (++in < total) {
+ b3 = fBuffer[in] & 0x00FF;
+ }
+ else {
+ b3 = fInputStream.read();
+ if (b3 == -1) {
+ if (out > offset) {
+ fBuffer[0] = (byte)b0;
+ fBuffer[1] = (byte)b1;
+ fBuffer[2] = (byte)b2;
+ fOffset = 3;
+ return out - offset;
+ }
+ expectedByte(4, 4);
+ }
+ count++;
+ }
+ if ((b3 & 0xC0) != 0x80) {
+ if (out > offset) {
+ fBuffer[0] = (byte)b0;
+ fBuffer[1] = (byte)b1;
+ fBuffer[2] = (byte)b2;
+ fBuffer[3] = (byte)b3;
+ fOffset = 4;
+ return out - offset;
+ }
+ invalidByte(4, 4, b2);
+ }
+
+ // decode bytes into surrogate characters
+ int uuuuu = ((b0 << 2) & 0x001C) | ((b1 >> 4) & 0x0003);
+ if (uuuuu > 0x10) {
+ invalidSurrogate(uuuuu);
+ }
+ int wwww = uuuuu - 1;
+ int zzzz = b1 & 0x000F;
+ int yyyyyy = b2 & 0x003F;
+ int xxxxxx = b3 & 0x003F;
+ int hs = 0xD800 | ((wwww << 6) & 0x03C0) | (zzzz << 2) | (yyyyyy >> 4);
+ int ls = 0xDC00 | ((yyyyyy << 6) & 0x03C0) | xxxxxx;
+
+ // set characters
+ ch[out++] = (char)hs;
+ ch[out++] = (char)ls;
+ count -= 2;
+ continue;
+ }
+
+ // error
+ if (out > offset) {
+ fBuffer[0] = (byte)b0;
+ fOffset = 1;
+ return out - offset;
+ }
+ invalidByte(1, 1, b0);
+ }
+
+ // return number of characters converted
+ if (DEBUG_READ) {
+ if (log.isDebugEnabled())
+ log.debug("read(char[],"+offset+','+length+"): count="+count);
+ }
+ return count;
+
+ } // read(char[],int,int)
+
+ /**
+ * Skip characters. This method will block until some characters are
+ * available, an I/O error occurs, or the end of the stream is reached.
+ *
+ * @param n The number of characters to skip
+ *
+ * @return The number of characters actually skipped
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public long skip(long n) throws IOException {
+
+ long remaining = n;
+ final char[] ch = new char[fBuffer.length];
+ do {
+ int length = ch.length < remaining ? ch.length : (int)remaining;
+ int count = read(ch, 0, length);
+ if (count > 0) {
+ remaining -= count;
+ }
+ else {
+ break;
+ }
+ } while (remaining > 0);
+
+ long skipped = n - remaining;
+ return skipped;
+
+ } // skip(long):long
+
+ /**
+ * Tell whether this stream is ready to be read.
+ *
+ * @return True if the next read() is guaranteed not to block for input,
+ * false otherwise. Note that returning false does not guarantee that the
+ * next read will block.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public boolean ready() throws IOException {
+ return false;
+ } // ready()
+
+ /**
+ * Tell whether this stream supports the mark() operation.
+ */
+ public boolean markSupported() {
+ return false;
+ } // markSupported()
+
+ /**
+ * Mark the present position in the stream. Subsequent calls to reset()
+ * will attempt to reposition the stream to this point. Not all
+ * character-input streams support the mark() operation.
+ *
+ * @param readAheadLimit Limit on the number of characters that may be
+ * read while still preserving the mark. After
+ * reading this many characters, attempting to
+ * reset the stream may fail.
+ *
+ * @exception IOException If the stream does not support mark(),
+ * or if some other I/O error occurs
+ */
+ public void mark(int readAheadLimit) throws IOException {
+ throw new IOException(
+ Localizer.getMessage("jsp.error.xml.operationNotSupported",
+ "mark()", "UTF-8"));
+ }
+
+ /**
+ * Reset the stream. If the stream has been marked, then attempt to
+ * reposition it at the mark. If the stream has not been marked, then
+ * attempt to reset it in some way appropriate to the particular stream,
+ * for example by repositioning it to its starting point. Not all
+ * character-input streams support the reset() operation, and some support
+ * reset() without supporting mark().
+ *
+ * @exception IOException If the stream has not been marked,
+ * or if the mark has been invalidated,
+ * or if the stream does not support reset(),
+ * or if some other I/O error occurs
+ */
+ public void reset() throws IOException {
+ fOffset = 0;
+ fSurrogate = -1;
+ } // reset()
+
+ /**
+ * Close the stream. Once a stream has been closed, further read(),
+ * ready(), mark(), or reset() invocations will throw an IOException.
+ * Closing a previously-closed stream, however, has no effect.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void close() throws IOException {
+ fInputStream.close();
+ } // close()
+
+ //
+ // Private methods
+ //
+
+ /** Throws an exception for expected byte. */
+ private void expectedByte(int position, int count)
+ throws UTFDataFormatException {
+
+ throw new UTFDataFormatException(
+ Localizer.getMessage("jsp.error.xml.expectedByte",
+ Integer.toString(position),
+ Integer.toString(count)));
+
+ } // expectedByte(int,int,int)
+
+ /** Throws an exception for invalid byte. */
+ private void invalidByte(int position, int count, int c)
+ throws UTFDataFormatException {
+
+ throw new UTFDataFormatException(
+ Localizer.getMessage("jsp.error.xml.invalidByte",
+ Integer.toString(position),
+ Integer.toString(count)));
+ } // invalidByte(int,int,int,int)
+
+ /** Throws an exception for invalid surrogate bits. */
+ private void invalidSurrogate(int uuuuu) throws UTFDataFormatException {
+
+ throw new UTFDataFormatException(
+ Localizer.getMessage("jsp.error.xml.invalidHighSurrogate",
+ Integer.toHexString(uuuuu)));
+ } // invalidSurrogate(int)
+
+} // class UTF8Reader