/* * 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.Serializable; /** * Base class for the *Chunk implementation to reduce duplication. */ public abstract class AbstractChunk implements Cloneable, Serializable { private static final long serialVersionUID = 1L; /* * JVMs may limit the maximum array size to slightly less than * Integer.MAX_VALUE. On markt's desktop the limit is MAX_VALUE - 2. * Comments in the JRE source code for ArrayList and other classes indicate * that it may be as low as MAX_VALUE - 8 on some systems. */ public static final int ARRAY_MAX_SIZE = Integer.MAX_VALUE - 8; private int hashCode = 0; protected boolean hasHashCode = false; protected boolean isSet; private int limit = -1; protected int start; protected int end; /** * Maximum amount of data in this buffer. If -1 or not set, the buffer will * grow to {{@link #ARRAY_MAX_SIZE}. 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. * * @param limit The new limit */ public void setLimit(int limit) { this.limit = limit; } public int getLimit() { return limit; } protected int getLimitInternal() { if (limit > 0) { return limit; } else { return ARRAY_MAX_SIZE; } } /** * @return the start position of the data in the buffer */ public int getStart() { return start; } public int getEnd() { return end; } public void setEnd(int i) { end = i; } // TODO: Deprecate offset and use start public int getOffset() { return start; } public void setOffset(int off) { if (end < off) { end = off; } start = off; } /** * @return the length of the data in the buffer */ public int getLength() { return end - start; } public boolean isNull() { if (end > 0) { return false; } return !isSet; } public int indexOf(String src, int srcOff, int srcLen, int myOff) { char first = src.charAt(srcOff); // Look for first char int srcEnd = srcOff + srcLen; mainLoop: for (int i = myOff + start; i <= (end - srcLen); i++) { if (getBufferElement(i) != first) { continue; } // found first char, now look for a match int myPos = i + 1; for (int srcPos = srcOff + 1; srcPos < srcEnd;) { if (getBufferElement(myPos++) != src.charAt(srcPos++)) { continue mainLoop; } } return i - start; // found it } return -1; } /** * Resets the chunk to an uninitialized state. */ public void recycle() { hasHashCode = false; isSet = false; start = 0; end = 0; } @Override public int hashCode() { if (hasHashCode) { return hashCode; } int code = 0; code = hash(); hashCode = code; hasHashCode = true; return code; } public int hash() { int code = 0; for (int i = start; i < end; i++) { code = code * 37 + getBufferElement(i); } return code; } protected abstract int getBufferElement(int index); }