📄 bytebuffer.java
字号:
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 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 acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", 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 names without prior written
* permission of the Apache Group.
*
* 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. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.util;
import java.io.*;
/**
* Un-synchronized byte buffer. We have methods to write and read from the
* buffer, and helpers can convert various data formats.
*
* The idea is to minimize the number of buffers and the amount of copy from
* layer to layer. It's _not_ premature optimization - it's the way things
* should work.
*
* The Request and Response will use several buffers, same for the protocol
* adapters.
*
* Note that the Buffer owns his byte[], while the Chunk is just a light
* cursor.
*
*
* @author Costin Manolache
*/
public class ByteBuffer {
// everything happens inside one thread !!!
BufferEvent bufferEvent=new BufferEvent(this);
BufferListener listeners[]=new BufferListener[10];
int listenerCount=0;
protected static final int DEFAULT_BUFFER_SIZE = 8*1024;
int defaultBufferSize = DEFAULT_BUFFER_SIZE;
int bytesWritten = 0;
/** The buffer
*/
public byte buf[];
public int start;
public int end;
/**
* The index one greater than the index of the last valid byte in
* the buffer.
*/
public int count;
// count==-1 for end of stream
Object parent; // Who "owns" this buffer
/**
* The current position in the buffer. This is the index of the next
* character to be read from the buf.
*/
public int pos;
final static int debug=0;
public ByteBuffer() {
buf=new byte[defaultBufferSize];
}
public void recycle() {
bytesWritten=0;
count=0;
pos=0;
}
public Object getParent() {
return parent;
}
public void setParent( Object o ) {
parent=o;
}
public void addBufferListener( BufferListener l ) {
listeners[listenerCount]=l;
listenerCount++;
}
public void doWrite( byte buf[], int off, int count ) {
bufferEvent.setByteBuffer( buf );
bufferEvent.setOffset( off );
bufferEvent.setLength( count );
for( int i=0; i< listenerCount; i++ )
listeners[i].bufferFull( bufferEvent );
}
public int doRead( byte buf[], int off, int count ) {
if( debug > 1 ) log("doRead " + off + " " + count);
bufferEvent.setByteBuffer( buf );
bufferEvent.setOffset( off );
bufferEvent.setLength( count );
for( int i=0; i< listenerCount; i++ )
listeners[i].bufferEmpty( bufferEvent );
return bufferEvent.getLength();
}
// -------------------- Adding to the buffer --------------------
// Like BufferedOutputStream, without sync
public void write(int b) throws IOException {
if( debug>0 ) log( "write(b)");
if( debug>1 )System.out.write( b );
if (count >= buf.length) {
flush();
}
buf[count++] = (byte)b;
bytesWritten++;
}
public void write(byte b[], int off, int len) throws IOException {
if( debug>0 ) log( "write(b[])" );
if( debug>1 ) System.out.write( b, off, len );
int avail=buf.length - count;
// fit in buffer, great.
if( len <= avail ) {
System.arraycopy(b, off, buf, count, len);
count += len;
bytesWritten += len;
return;
}
// Optimization:
// If len-avail < length ( i.e. after we fill the buffer with
// what we can, the remaining will fit in the buffer ) we'll just
// copy the first part, flush, then copy the second part - 1 write
// and still have some space for more. We'll still have 2 writes, but
// we write more on the first.
if (len - avail < buf.length) {
/* If the request length exceeds the size of the output buffer,
flush the output buffer and then write the data directly.
We can't avoid 2 writes, but we can write more on the second
*/
System.arraycopy(b, off, buf, count, avail);
count += avail;
flush(); // count will be 0
System.arraycopy(b, off+avail, buf, count, len - avail);
count+= len - avail;
bytesWritten += len - avail;
return;
}
// len > buf.length + avail
flush();
doWrite( b, off, len );
return;
}
public void flush() {
if( debug > 0 ) log("Flush");
if (count > 0) {
doWrite(buf, 0, count);
count = 0;
}
}
// public void close() {
// // a write with count=0 will make sure
// // the listeners are at least once called.
// // we need to add a close() notification
// System.out.println("Buffer.close()");
// doWrite( buf, 0, count);
// count=0;
// }
// -------------------- Extracting from buffer --------------------
// Like BufferedInputStream, without sync and without mark
public int read() {
if( count == -1 ) return -1;
if (pos >= count) {
fill();
if (count <0 )
return -1;
}
return buf[pos++] & 0xff;
}
public int read(byte b[], int off, int len)
throws IOException
{
if (len == 0) {
return 0;
}
int n=0; // how many bytes we copy
int avail = count - pos;
// copy from our buffer to the result
if( avail > 0 ) {
int cnt = (avail < len) ? avail : len;
System.arraycopy(buf, pos, b, off, cnt);
pos += cnt;
n=cnt;
}
if( n >= len ) return n;
// now our buffer is empty
/* If the requested length is at least as large as the buffer
do not bother to copy the bytes into the local buffer.
*/
if (len - n >= buf.length ) {
return n + doRead(b, off+n, len-n);
}
// fill the buffer, copy the remaining
fill();
avail = count - pos;
// EOF, we may have copied something from the buff
if (avail <= 0) return n;
// copy the remaining
int cnt = (avail < len - n ) ? avail : len - n ;
System.arraycopy(buf, pos, b, off+n, cnt);
pos += cnt;
n+=cnt;
return n;
}
private void fill() {
pos=0;
count = doRead( buf, 0, buf.length );
if( count==0) count=-1; // end of stream
}
// -------------------- BufferedOutputStream compatibility
public boolean isContentWritten() {
return bytesWritten!=0;
}
public void setBufferSize(int size) {
if( size > buf.length ) {
buf=new byte[size];
}
}
public int getBufferSize() {
return buf.length;
}
// -------------------- Utils
void log( String s ) {
System.out.println("ByteBuffer: " + s );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -