/* * This file is part of the OWASP Proxy, a free intercepting proxy library. * Copyright (C) 2008-2010 Rogan Dawes <rogan@dawes.za.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to: * The Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ package org.owasp.proxy.util; /** * This class implements a circular buffer that allows writing and reading to the buffer. Note: It is not inherently * thread safe! * * The idea is that data may be added to the buffer, and later read from it. The buffer will automatically grow to * ensure capacity for the data added to it. It does not currently shrink when the data is read from it. * * @author rogan * */ public class CircularByteBuffer { private byte[] buff; private int start = 0, length = 0; public CircularByteBuffer(int initialSize) { buff = new byte[initialSize]; } public int length() { return length; } public int getBufferSize() { return buff == null ? 0 : buff.length; } public int getCapacity() { return buff.length - length; } private void ensureCapacity(int bytes) { if (getCapacity() < bytes) { byte[] t = new byte[buff.length * 2]; if (length == 0) { // copy nothing } else if (start + length <= buff.length) { System.arraycopy(buff, start, t, 0, length); } else if (start + length > buff.length) { System.arraycopy(buff, start, t, 0, buff.length - start); System.arraycopy(buff, 0, t, (buff.length - start), length - (buff.length - start)); } start = 0; buff = t; } } public void add(byte i) { ensureCapacity(1); buff[(start + length) % buff.length] = i; length++; } public void add(byte[] b) { add(b, 0, b.length); } public void add(byte[] b, int off, int len) { ensureCapacity(len); int pos = (start + length) % buff.length; copyToBuffer(pos, b, off, len); length = length + len; } public void push(byte i) { ensureCapacity(1); int pos = 0; if (length > 0) { pos = start - 1; if (pos < 0) pos += buff.length; } buff[pos] = i; start = pos; length++; } public void push(byte[] b) { push(b, 0, b.length); } public void push(byte[] b, int off, int len) { ensureCapacity(len); int pos = 0; if (length > 0) { pos = start - len; if (pos < 0) pos += buff.length; } copyToBuffer(pos, b, off, len); start = pos; length += len; } private void copyToBuffer(int pos, byte[] b, int off, int len) { int l = buff.length - pos; if (l >= len) { // there is enough space in one chunk System.arraycopy(b, off, buff, pos, len); } else { // we have to wrap around System.arraycopy(b, off, buff, pos, l); System.arraycopy(b, off + l, buff, 0, len - l); } } private void copyFromBuffer(byte[] b, int off, int len) { int l = Math.min(buff.length - start, len); System.arraycopy(buff, start, b, off, l); if (l != len) System.arraycopy(buff, 0, b, off + l, len - l); } public int remove() { if (length == 0) return -1; int i = buff[start] & 0xFF; start = (start + 1) % buff.length; length--; return i; } public int remove(byte[] b) { return remove(b, 0, b.length); } public int remove(byte[] b, int off, int len) { if (length == 0) return -1; int read = Math.min(len, length); copyFromBuffer(b, off, read); start = (start + read) % buff.length; length = length - read; return read; } }