init
This commit is contained in:
192
java/org/apache/tomcat/util/buf/C2BConverter.java
Normal file
192
java/org/apache/tomcat/util/buf/C2BConverter.java
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* 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.tomcat.util.buf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
|
||||
/**
|
||||
* NIO based character encoder.
|
||||
*/
|
||||
public final class C2BConverter {
|
||||
|
||||
private final CharsetEncoder encoder;
|
||||
private ByteBuffer bb = null;
|
||||
private CharBuffer cb = null;
|
||||
|
||||
/**
|
||||
* Leftover buffer used for multi-characters characters.
|
||||
*/
|
||||
private final CharBuffer leftovers;
|
||||
|
||||
public C2BConverter(Charset charset) {
|
||||
encoder = charset.newEncoder();
|
||||
encoder.onUnmappableCharacter(CodingErrorAction.REPLACE)
|
||||
.onMalformedInput(CodingErrorAction.REPLACE);
|
||||
char[] left = new char[4];
|
||||
leftovers = CharBuffer.wrap(left);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the encoder state.
|
||||
*/
|
||||
public void recycle() {
|
||||
encoder.reset();
|
||||
leftovers.position(0);
|
||||
}
|
||||
|
||||
public boolean isUndeflow() {
|
||||
return (leftovers.position() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given characters to bytes.
|
||||
*
|
||||
* @param cc char input
|
||||
* @param bc byte output
|
||||
* @throws IOException An encoding error occurred
|
||||
*/
|
||||
public void convert(CharChunk cc, ByteChunk bc) throws IOException {
|
||||
if ((bb == null) || (bb.array() != bc.getBuffer())) {
|
||||
// Create a new byte buffer if anything changed
|
||||
bb = ByteBuffer.wrap(bc.getBuffer(), bc.getEnd(), bc.getBuffer().length - bc.getEnd());
|
||||
} else {
|
||||
// Initialize the byte buffer
|
||||
bb.limit(bc.getBuffer().length);
|
||||
bb.position(bc.getEnd());
|
||||
}
|
||||
if ((cb == null) || (cb.array() != cc.getBuffer())) {
|
||||
// Create a new char buffer if anything changed
|
||||
cb = CharBuffer.wrap(cc.getBuffer(), cc.getStart(), cc.getLength());
|
||||
} else {
|
||||
// Initialize the char buffer
|
||||
cb.limit(cc.getEnd());
|
||||
cb.position(cc.getStart());
|
||||
}
|
||||
CoderResult result = null;
|
||||
// Parse leftover if any are present
|
||||
if (leftovers.position() > 0) {
|
||||
int pos = bb.position();
|
||||
// Loop until one char is encoded or there is a encoder error
|
||||
do {
|
||||
leftovers.put((char) cc.substract());
|
||||
leftovers.flip();
|
||||
result = encoder.encode(leftovers, bb, false);
|
||||
leftovers.position(leftovers.limit());
|
||||
leftovers.limit(leftovers.array().length);
|
||||
} while (result.isUnderflow() && (bb.position() == pos));
|
||||
if (result.isError() || result.isMalformed()) {
|
||||
result.throwException();
|
||||
}
|
||||
cb.position(cc.getStart());
|
||||
leftovers.position(0);
|
||||
}
|
||||
// Do the decoding and get the results into the byte chunk and the char
|
||||
// chunk
|
||||
result = encoder.encode(cb, bb, false);
|
||||
if (result.isError() || result.isMalformed()) {
|
||||
result.throwException();
|
||||
} else if (result.isOverflow()) {
|
||||
// Propagate current positions to the byte chunk and char chunk
|
||||
bc.setEnd(bb.position());
|
||||
cc.setOffset(cb.position());
|
||||
} else if (result.isUnderflow()) {
|
||||
// Propagate current positions to the byte chunk and char chunk
|
||||
bc.setEnd(bb.position());
|
||||
cc.setOffset(cb.position());
|
||||
// Put leftovers in the leftovers char buffer
|
||||
if (cc.getLength() > 0) {
|
||||
leftovers.limit(leftovers.array().length);
|
||||
leftovers.position(cc.getLength());
|
||||
cc.substract(leftovers.array(), 0, cc.getLength());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given characters to bytes.
|
||||
*
|
||||
* @param cc char input
|
||||
* @param bc byte output
|
||||
* @throws IOException An encoding error occurred
|
||||
*/
|
||||
public void convert(CharBuffer cc, ByteBuffer bc) throws IOException {
|
||||
if ((bb == null) || (bb.array() != bc.array())) {
|
||||
// Create a new byte buffer if anything changed
|
||||
bb = ByteBuffer.wrap(bc.array(), bc.limit(), bc.capacity() - bc.limit());
|
||||
} else {
|
||||
// Initialize the byte buffer
|
||||
bb.limit(bc.capacity());
|
||||
bb.position(bc.limit());
|
||||
}
|
||||
if ((cb == null) || (cb.array() != cc.array())) {
|
||||
// Create a new char buffer if anything changed
|
||||
cb = CharBuffer.wrap(cc.array(), cc.arrayOffset() + cc.position(), cc.remaining());
|
||||
} else {
|
||||
// Initialize the char buffer
|
||||
cb.limit(cc.limit());
|
||||
cb.position(cc.position());
|
||||
}
|
||||
CoderResult result = null;
|
||||
// Parse leftover if any are present
|
||||
if (leftovers.position() > 0) {
|
||||
int pos = bb.position();
|
||||
// Loop until one char is encoded or there is a encoder error
|
||||
do {
|
||||
leftovers.put(cc.get());
|
||||
leftovers.flip();
|
||||
result = encoder.encode(leftovers, bb, false);
|
||||
leftovers.position(leftovers.limit());
|
||||
leftovers.limit(leftovers.array().length);
|
||||
} while (result.isUnderflow() && (bb.position() == pos));
|
||||
if (result.isError() || result.isMalformed()) {
|
||||
result.throwException();
|
||||
}
|
||||
cb.position(cc.position());
|
||||
leftovers.position(0);
|
||||
}
|
||||
// Do the decoding and get the results into the byte chunk and the char
|
||||
// chunk
|
||||
result = encoder.encode(cb, bb, false);
|
||||
if (result.isError() || result.isMalformed()) {
|
||||
result.throwException();
|
||||
} else if (result.isOverflow()) {
|
||||
// Propagate current positions to the byte chunk and char chunk
|
||||
bc.limit(bb.position());
|
||||
cc.position(cb.position());
|
||||
} else if (result.isUnderflow()) {
|
||||
// Propagate current positions to the byte chunk and char chunk
|
||||
bc.limit(bb.position());
|
||||
cc.position(cb.position());
|
||||
// Put leftovers in the leftovers char buffer
|
||||
if (cc.remaining() > 0) {
|
||||
leftovers.limit(leftovers.array().length);
|
||||
leftovers.position(cc.remaining());
|
||||
cc.get(leftovers.array(), 0, cc.remaining());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Charset getCharset() {
|
||||
return encoder.charset();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user