001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.tomcat.util.buf;
019:
020: import java.io.IOException;
021:
022: /**
023: * Moved from ByteChunk - code to convert from UTF8 bytes to chars.
024: * Not used in the current tomcat3.3 : the performance gain is not very
025: * big if the String is created, only if we avoid that and work only
026: * on char[]. Until than, it's better to be safe. ( I tested this code
027: * with 2 and 3 bytes chars, and it works fine in xerces )
028: *
029: * Cut from xerces' UTF8Reader.copyMultiByteCharData()
030: *
031: * @author Costin Manolache
032: * @author ( Xml-Xerces )
033: */
034: public final class UTF8Decoder extends B2CConverter {
035:
036: private static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
037: .getLog(UTF8Decoder.class);
038:
039: // may have state !!
040:
041: public UTF8Decoder() {
042:
043: }
044:
045: public void recycle() {
046: }
047:
048: public void convert(ByteChunk mb, CharChunk cb) throws IOException {
049: int bytesOff = mb.getOffset();
050: int bytesLen = mb.getLength();
051: byte bytes[] = mb.getBytes();
052:
053: int j = bytesOff;
054: int end = j + bytesLen;
055:
056: while (j < end) {
057: int b0 = 0xff & bytes[j];
058:
059: if ((b0 & 0x80) == 0) {
060: cb.append((char) b0);
061: j++;
062: continue;
063: }
064:
065: // 2 byte ?
066: if (j++ >= end) {
067: // ok, just ignore - we could throw exception
068: throw new IOException("Conversion error - EOF ");
069: }
070: int b1 = 0xff & bytes[j];
071:
072: // ok, let's the fun begin - we're handling UTF8
073: if ((0xe0 & b0) == 0xc0) { // 110yyyyy 10xxxxxx (0x80 to 0x7ff)
074: int ch = ((0x1f & b0) << 6) + (0x3f & b1);
075: if (debug > 0)
076: log("Convert " + b0 + " " + b1 + " " + ch
077: + ((char) ch));
078:
079: cb.append((char) ch);
080: j++;
081: continue;
082: }
083:
084: if (j++ >= end)
085: return;
086: int b2 = 0xff & bytes[j];
087:
088: if ((b0 & 0xf0) == 0xe0) {
089: if ((b0 == 0xED && b1 >= 0xA0)
090: || (b0 == 0xEF && b1 == 0xBF && b2 >= 0xBE)) {
091: if (debug > 0)
092: log("Error " + b0 + " " + b1 + " " + b2);
093:
094: throw new IOException("Conversion error 2");
095: }
096:
097: int ch = ((0x0f & b0) << 12) + ((0x3f & b1) << 6)
098: + (0x3f & b2);
099: cb.append((char) ch);
100: if (debug > 0)
101: log("Convert " + b0 + " " + b1 + " " + b2 + " "
102: + ch + ((char) ch));
103: j++;
104: continue;
105: }
106:
107: if (j++ >= end)
108: return;
109: int b3 = 0xff & bytes[j];
110:
111: if ((0xf8 & b0) == 0xf0) {
112: if (b0 > 0xF4 || (b0 == 0xF4 && b1 >= 0x90)) {
113: if (debug > 0)
114: log("Convert " + b0 + " " + b1 + " " + b2 + " "
115: + b3);
116: throw new IOException("Conversion error ");
117: }
118: int ch = ((0x0f & b0) << 18) + ((0x3f & b1) << 12)
119: + ((0x3f & b2) << 6) + (0x3f & b3);
120:
121: if (debug > 0)
122: log("Convert " + b0 + " " + b1 + " " + b2 + " "
123: + b3 + " " + ch + ((char) ch));
124:
125: if (ch < 0x10000) {
126: cb.append((char) ch);
127: } else {
128: cb
129: .append((char) (((ch - 0x00010000) >> 10) + 0xd800));
130: cb
131: .append((char) (((ch - 0x00010000) & 0x3ff) + 0xdc00));
132: }
133: j++;
134: continue;
135: } else {
136: // XXX Throw conversion exception !!!
137: if (debug > 0)
138: log("Convert " + b0 + " " + b1 + " " + b2 + " "
139: + b3);
140: throw new IOException("Conversion error 4");
141: }
142: }
143: }
144:
145: private static int debug = 1;
146:
147: void log(String s) {
148: if (log.isDebugEnabled())
149: log.debug("UTF8Decoder: " + s);
150: }
151:
152: }
|