FileDocCategorySizeDatePackage
CharChunk.javaAPI DocApache Tomcat 6.0.1417800Fri Jul 20 04:20:32 BST 2007org.apache.tomcat.util.buf

CharChunk

public final class CharChunk extends Object implements Serializable, CharSequence, Cloneable
Utilities to manipluate char chunks. While String is the easiest way to manipulate chars ( search, substrings, etc), it is known to not be the most efficient solution - Strings are designed as imutable and secure objects.
author
dac@sun.com
author
James Todd [gonzo@sun.com]
author
Costin Manolache
author
Remy Maucherat

Fields Summary
private char[]
buff
private int
start
private int
end
private boolean
isSet
private boolean
isOutput
private int
limit
private CharInputChannel
in
private CharOutputChannel
out
private boolean
optimizedWrite
Constructors Summary
public CharChunk()
Creates a new, uninitialized CharChunk object.


               
      
    
public CharChunk(int size)

	allocate( size, -1 );
    
Methods Summary
public voidallocate(int initial, int limit)

	isOutput=true;
	if( buff==null || buff.length < initial ) {
	    buff=new char[initial];
	}
	this.limit=limit;
	start=0;
	end=0;
	isOutput=true;
	isSet=true;
    
public voidappend(char b)

	makeSpace( 1 );

	// couldn't make space
	if( limit >0 && end >= limit ) {
	    flushBuffer();
	}
	buff[end++]=b;
    
public voidappend(org.apache.tomcat.util.buf.CharChunk src)

	append( src.getBuffer(), src.getOffset(), src.getLength());
    
public voidappend(char[] src, int off, int len)
Add data to the buffer

	// will grow, up to limit
	makeSpace( len );

	// if we don't have limit: makeSpace can grow as it wants
	if( limit < 0 ) {
	    // assert: makeSpace made enough space
	    System.arraycopy( src, off, buff, end, len );
	    end+=len;
	    return;
	}

        // Optimize on a common case.
        // If the source is going to fill up all the space in buffer, may
        // as well write it directly to the output, and avoid an extra copy
        if ( optimizedWrite && len == limit && end == start && out != null ) {
            out.realWriteChars( src, off, len );
            return;
        }
	
	// if we have limit and we're below
	if( len <= limit - end ) {
	    // makeSpace will grow the buffer to the limit,
	    // so we have space
	    System.arraycopy( src, off, buff, end, len );
            
	    end+=len;
	    return;
	}

	// need more space than we can afford, need to flush
	// buffer

	// the buffer is already at ( or bigger than ) limit
	
	// 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 + end < 2 * limit ) {
	    /* 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
	    */
	    int avail=limit-end;
	    System.arraycopy(src, off, buff, end, avail);
	    end += avail;
	    
	    flushBuffer();
	    
	    System.arraycopy(src, off+avail, buff, end, len - avail);
	    end+= len - avail;
	    
	} else {	// len > buf.length + avail
	    // long write - flush the buffer and write the rest
	    // directly from source
	    flushBuffer();
	    
	    out.realWriteChars( src, off, len );
	}
    
public voidappend(java.lang.StringBuffer sb)
Add data to the buffer

	int len=sb.length();

	// will grow, up to limit
	makeSpace( len );

	// if we don't have limit: makeSpace can grow as it wants
	if( limit < 0 ) {
	    // assert: makeSpace made enough space
	    sb.getChars(0, len, buff, end );
	    end+=len;
	    return;
	}

	int off=0;
	int sbOff = off;
	int sbEnd = off + len;
	while (sbOff < sbEnd) {
	    int d = min(limit - end, sbEnd - sbOff);
	    sb.getChars( sbOff, sbOff+d, buff, end);
	    sbOff += d;
	    end += d;
	    if (end >= limit)
		flushBuffer();
	}
    
public voidappend(java.lang.String s)
Append a string to the buffer

        append(s, 0, s.length());
    
public voidappend(java.lang.String s, int off, int len)
Append a string to the buffer

	if (s==null) return;
	
	// will grow, up to limit
	makeSpace( len );

	// if we don't have limit: makeSpace can grow as it wants
	if( limit < 0 ) {
	    // assert: makeSpace made enough space
	    s.getChars(off, off+len, buff, end );
	    end+=len;
	    return;
	}

	int sOff = off;
	int sEnd = off + len;
	while (sOff < sEnd) {
	    int d = min(limit - end, sEnd - sOff);
	    s.getChars( sOff, sOff+d, buff, end);
	    sOff += d;
	    end += d;
	    if (end >= limit)
		flushBuffer();
	}
    
public charcharAt(int index)

        return buff[index + start];
    
public booleanequals(java.lang.String s)
Compares the message bytes to the specified String object.

param
s the String to compare
return
true if the comparison succeeded, false otherwise

	char[] c = buff;
	int len = end-start;
	if (c == null || len != s.length()) {
	    return false;
	}
	int off = start;
	for (int i = 0; i < len; i++) {
	    if (c[off++] != s.charAt(i)) {
		return false;
	    }
	}
	return true;
    
public booleanequals(org.apache.tomcat.util.buf.CharChunk cc)

	return equals( cc.getChars(), cc.getOffset(), cc.getLength());
    
public booleanequals(char[] b2, int off2, int len2)

	char b1[]=buff;
	if( b1==null && b2==null ) return true;
	
	if (b1== null || b2==null || end-start != len2) {
	    return false;
	}
	int off1 = start;
	int len=end-start;
	while ( len-- > 0) {
	    if (b1[off1++] != b2[off2++]) {
		return false;
	    }
	}
	return true;
    
public booleanequals(byte[] b2, int off2, int len2)

	char b1[]=buff;
	if( b2==null && b1==null ) return true;

	if (b1== null || b2==null || end-start != len2) {
	    return false;
	}
	int off1 = start;
	int len=end-start;
	
	while ( len-- > 0) {
	    if ( b1[off1++] != (char)b2[off2++]) {
		return false;
	    }
	}
	return true;
    
public booleanequalsIgnoreCase(java.lang.String s)
Compares the message bytes to the specified String object.

param
s the String to compare
return
true if the comparison succeeded, false otherwise

	char[] c = buff;
	int len = end-start;
	if (c == null || len != s.length()) {
	    return false;
	}
	int off = start;
	for (int i = 0; i < len; i++) {
	    if (Ascii.toLower( c[off++] ) != Ascii.toLower( s.charAt(i))) {
		return false;
	    }
	}
	return true;
    
public voidflushBuffer()

	//assert out!=null
	if( out==null ) {
	    throw new IOException( "Buffer overflow, no sink " + limit + " " +
				   buff.length  );
	}
	out.realWriteChars( buff, start, end - start );
	end=start;
    
public char[]getBuffer()

	return buff;
    
public char[]getChars()

	return getBuffer();
    
public org.apache.tomcat.util.buf.CharChunkgetClone()

	try {
	    return (CharChunk)this.clone();
	} catch( Exception ex) {
	    return null;
	}
    
public intgetEnd()

	return end;
    
public intgetInt()

	return Ascii.parseInt(buff, start,
				end-start);
    
public intgetLength()
Returns the length of the bytes.

	return end-start;
    
public intgetLimit()

	return limit;
    
public intgetOffset()

	return start;
    
public intgetStart()
Returns the start offset of the bytes. For output this is the end of the buffer.

	return start;
    
public inthash()

	int code=0;
	for (int i = start; i < start + end-start; i++) {
	    code = code * 37 + buff[i];
	}
	return code;
    
public inthashIgnoreCase()

	int code=0;
	for (int i = start; i < end; i++) {
	    code = code * 37 + Ascii.toLower(buff[i]);
	}
	return code;
    
public intindexOf(char c)

	return indexOf( c, start);
    
public intindexOf(char c, int starting)
Returns true if the message bytes starts with the specified string.

param
c the character

	int ret = indexOf( buff, start+starting, end, c );
	return (ret >= start) ? ret - start : -1;
    
public static intindexOf(char[] chars, int off, int cend, char qq)

	while( off < cend ) {
	    char b=chars[off];
	    if( b==qq )
		return off;
	    off++;
	}
	return -1;
    
public intindexOf(java.lang.String src, int srcOff, int srcLen, int myOff)

	char first=src.charAt( srcOff );

	// Look for first char 
	int srcEnd = srcOff + srcLen;
        
	for( int i=myOff+start; i <= (end - srcLen); i++ ) {
	    if( buff[i] != first ) continue;
	    // found first char, now look for a match
            int myPos=i+1;
	    for( int srcPos=srcOff + 1; srcPos< srcEnd; ) {
                if( buff[myPos++] != src.charAt( srcPos++ ))
		    break;
                if( srcPos==srcEnd ) return i-start; // found it
	    }
	}
	return -1;
    
public booleanisNull()

	if( end > 0 ) return false;
	return !isSet; //XXX 
    
public intlength()

        return end - start;
    
private voidmakeSpace(int count)
Make space for len chars. If len is small, allocate a reserve space too. Never grow bigger than limit.

	char[] tmp = null;

	int newSize;
	int desiredSize=end + count;

	// Can't grow above the limit
	if( limit > 0 &&
	    desiredSize > limit) {
	    desiredSize=limit;
	}

	if( buff==null ) {
	    if( desiredSize < 256 ) desiredSize=256; // take a minimum
	    buff=new char[desiredSize];
	}

	// limit < buf.length ( the buffer is already big )
	// or we already have space XXX
	if( desiredSize <= buff.length) {
	    return;
	}
	// grow in larger chunks
	if( desiredSize < 2 * buff.length ) {
	    newSize= buff.length * 2;
	    if( limit >0 &&
		newSize > limit ) newSize=limit;
	    tmp=new char[newSize];
	} else {
	    newSize= buff.length * 2 + count ;
	    if( limit > 0 &&
		newSize > limit ) newSize=limit;
	    tmp=new char[newSize];
	}
	
	System.arraycopy(buff, start, tmp, start, end-start);
	buff = tmp;
	tmp = null;
    
private intmin(int a, int b)

	if (a < b) return a;
	return b;
    
public voidrecycle()
Resets the message bytes to an uninitialized state.

	//	buff=null;
	isSet=false; // XXX
	start=0;
	end=0;
    
public voidreset()

	buff=null;
    
public voidsetCharInputChannel(org.apache.tomcat.util.buf.CharChunk$CharInputChannel in)
When the buffer is empty, read the data from the input channel.

        this.in = in;
    
public voidsetCharOutputChannel(org.apache.tomcat.util.buf.CharChunk$CharOutputChannel out)
When the buffer is full, write the data to the output channel. Also used when large amount of data is appended. If not set, the buffer will grow to the limit.

	this.out=out;
    
public voidsetChars(char[] c, int off, int len)

        buff=c;
        start=off;
        end=start + len;
        isSet=true;
    
public voidsetEnd(int i)

	end=i;
    
public voidsetLimit(int limit)
Maximum amount of data in this buffer. If -1 or not set, the buffer will grow undefinitely. Can be smaller than the current buffer size ( which will not shrink ). When the limit is reached, the buffer will be flushed ( if out is set ) or throw exception.

	this.limit=limit;
    
public voidsetOffset(int off)
Returns the start offset of the bytes.

	start=off;
    
public voidsetOptimizedWrite(boolean optimizedWrite)

        this.optimizedWrite = optimizedWrite;
    
public booleanstartsWith(java.lang.String s)
Returns true if the message bytes starts with the specified string.

param
s the string

	char[] c = buff;
	int len = s.length();
	if (c == null || len > end-start) {
	    return false;
	}
	int off = start;
	for (int i = 0; i < len; i++) {
	    if (c[off++] != s.charAt(i)) {
		return false;
	    }
	}
	return true;
    
public booleanstartsWithIgnoreCase(java.lang.String s, int pos)
Returns true if the message bytes starts with the specified string.

param
s the string

	char[] c = buff;
	int len = s.length();
	if (c == null || len+pos > end-start) {
	    return false;
	}
	int off = start+pos;
	for (int i = 0; i < len; i++) {
	    if (Ascii.toLower( c[off++] ) != Ascii.toLower( s.charAt(i))) {
		return false;
	    }
	}
	return true;
    
public java.lang.CharSequencesubSequence(int start, int end)

        try {
            CharChunk result = (CharChunk) this.clone();
            result.setOffset(this.start + start);
            result.setEnd(this.start + end);
            return result;
        } catch (CloneNotSupportedException e) {
            // Cannot happen
            return null;
        }
    
public intsubstract()


        if ((end - start) == 0) {
            if (in == null)
                return -1;
            int n = in.realReadChars(buff, end, buff.length - end);
            if (n < 0)
                return -1;
        }

        return (buff[start++]);

    
public intsubstract(org.apache.tomcat.util.buf.CharChunk src)


        if ((end - start) == 0) {
            if (in == null)
                return -1;
            int n = in.realReadChars( buff, end, buff.length - end);
            if (n < 0)
                return -1;
        }

        int len = getLength();
        src.append(buff, start, len);
        start = end;
        return len;

    
public intsubstract(char[] src, int off, int len)


        if ((end - start) == 0) {
            if (in == null)
                return -1;
            int n = in.realReadChars( buff, end, buff.length - end);
            if (n < 0)
                return -1;
        }

        int n = len;
        if (len > getLength()) {
            n = getLength();
        }
        System.arraycopy(buff, start, src, off, n);
        start += n;
        return n;

    
public java.lang.StringtoString()

        if (null == buff) {
            return null;
        } else if (end-start == 0) {
            return "";
        }
        return StringCache.toString(this);
    
public java.lang.StringtoStringInternal()

        return new String(buff, start, end-start);