001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.jlan; 029 030import org.opencms.util.CmsStringUtil; 031 032import java.util.ArrayList; 033import java.util.Arrays; 034import java.util.List; 035 036/** 037 * Byte buffer class which expands dynamically if bytes are written to its end.<p> 038 */ 039public class CmsByteBuffer { 040 041 /** The internal byte buffer. */ 042 private byte[] m_buffer; 043 044 /** The current size (may be less than the length of the byte buffer). */ 045 private int m_size; 046 047 /** 048 * Creates a new instance.<p> 049 */ 050 public CmsByteBuffer() { 051 052 this(5); 053 } 054 055 /** 056 * Creates a new instance with a given initial capacity.<p> 057 * 058 * @param capacity the initial capacity 059 */ 060 public CmsByteBuffer(int capacity) { 061 062 m_buffer = new byte[Math.max(capacity, 5)]; 063 m_size = 0; 064 } 065 066 /** 067 * Gets the current length of the internal byte buffer, which is the number of bytes this buffer 068 * can contain before a new buffer is allocated.<p> 069 * 070 * @return the current length of the internal buffer 071 */ 072 public int getCapacity() { 073 074 return m_buffer.length; 075 } 076 077 /** 078 * Transfers bytes from this buffer to a target byte array.<p> 079 * 080 * @param dest the byte array to which the bytes should be transferred 081 * @param srcStart the start index in this buffer 082 * @param destStart the start index in the destination buffer 083 * 084 * @param len the number of bytes to transfer 085 */ 086 public void readBytes(byte[] dest, int srcStart, int destStart, int len) { 087 088 System.arraycopy(m_buffer, srcStart, dest, destStart, len); 089 090 } 091 092 /** 093 * Returns the logical size of this buffer (which may be less than its capacity).<p> 094 * 095 * @return the buffer size 096 */ 097 public int size() { 098 099 return m_size; 100 } 101 102 /** 103 * @see java.lang.Object#toString() 104 */ 105 @Override 106 public String toString() { 107 108 List<String> fragments = new ArrayList<String>(); 109 fragments.add("["); 110 int i = 0; 111 for (byte b : m_buffer) { 112 if (i == m_size) { 113 fragments.add("|"); 114 } 115 fragments.add("" + b); 116 i += 1; 117 } 118 fragments.add("]"); 119 return CmsStringUtil.listAsString(fragments, " "); 120 } 121 122 /** 123 * Changes the logical size of this buffer.<p> 124 * 125 * If the size is larger than the current size, the new space will be filled with 0s. 126 * Note that the internal byte buffer will not be shrunk if the size is smaller than the current 127 * size.<p> 128 * 129 * @param size the new size 130 */ 131 public void truncate(int size) { 132 133 ensureCapacity(size); 134 int minSize = Math.min(size, m_size); 135 int maxSize = Math.max(size, m_size); 136 Arrays.fill(m_buffer, minSize, maxSize, (byte)0); 137 m_size = size; 138 } 139 140 /** 141 * Writes some bytes to this buffer, expanding the buffer if necessary.<p> 142 * 143 * @param src the source from which to write the bytes 144 * @param srcStart the start index in the source array 145 * @param destStart the start index in this buffer 146 * 147 * @param len the number of bytes to write 148 */ 149 public void writeBytes(byte[] src, int srcStart, int destStart, int len) { 150 151 int newEnd = destStart + len; 152 ensureCapacity(newEnd); 153 if (newEnd > m_size) { 154 m_size = newEnd; 155 } 156 System.arraycopy(src, srcStart, m_buffer, destStart, len); 157 } 158 159 /** 160 * Make sure that the internal byte buffer can store at least requestedCapacity of bytes 161 * by reallocating it if necessary.<p> 162 * 163 * @param requestedCapacity the requested capacity 164 */ 165 private void ensureCapacity(int requestedCapacity) { 166 167 if (requestedCapacity > getCapacity()) { 168 int newCapacity = getCapacity(); 169 while (requestedCapacity > newCapacity) { 170 newCapacity = (newCapacity * 3) / 2; 171 } 172 reallocateBuffer(newCapacity); 173 } 174 } 175 176 /** 177 * Reallocates the internal byte buffer with a new capacity.<p> 178 * 179 * @param newCapacity the new capacity 180 */ 181 private void reallocateBuffer(int newCapacity) { 182 183 byte[] newBuffer = new byte[newCapacity]; 184 System.arraycopy(m_buffer, 0, newBuffer, 0, Math.min(m_size, newCapacity)); 185 m_buffer = newBuffer; 186 } 187 188}