001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *  
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *  
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License. 
018 *  
019 */
020package org.apache.directory.api.util;
021
022
023import org.apache.directory.api.i18n.I18n;
024
025
026/**
027 * A dynamically growing byte[]. 
028 *
029 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
030 */
031public class ByteBuffer
032{
033    /** the default initial buffer size */
034    private static final int DEFAULT_INITIAL_SIZE = 10;
035
036    /** the initial size of the buffer in number of bytes: also increment for allocations */
037    private final int initialSize;
038
039    /** the position into the buffer */
040    private int pos = 0;
041
042    /** the bytes of the buffer */
043    private byte[] buf;
044
045    /**
046     * Create a default ByteBuffer capable of holding 10 bytes
047     */
048    public ByteBuffer()
049    {
050        this( DEFAULT_INITIAL_SIZE );
051    }
052
053
054    /**
055     * Creates a ByteBuffer which has an initialze size
056     *  
057     * @param initialSize The initial buffer size
058     */
059    public ByteBuffer( int initialSize )
060    {
061        if ( initialSize <= 0 )
062        {
063            throw new IllegalArgumentException( I18n.err( I18n.ERR_04354 ) );
064        }
065
066        this.initialSize = initialSize;
067        this.buf = new byte[initialSize];
068    }
069
070
071    /**
072     * Reset the Buffer position to 0. Every new added byte will be put on position 0.
073     * Note that whatever this buffer contained before a call to the clear() method
074     * will not be removed.
075     */
076    public final void clear()
077    {
078        pos = 0;
079    }
080
081
082    /**
083     * @return The current position in the buffer
084     */
085    public final int position()
086    {
087        return pos;
088    }
089
090
091    /**
092     * @return The number of bytes that can be added into this buffer
093     */
094    public final int capacity()
095    {
096        return buf.length;
097    }
098
099
100    /**
101     * Returns the byte at a given position. Note that no control is done
102     * on the position validity.
103     * 
104     * @param i The position
105     * @return The byte at the given position in the buffer
106     */
107    public final byte get( int i )
108    {
109        return buf[i];
110    }
111
112
113    /**
114     * Get's the bytes, the backing store for this buffer.  Note
115     * that you need to use the position index to determine where
116     * to stop reading from this buffer.
117     * 
118     * @return The interned Byte[]
119     */
120    public final byte[] buffer()
121    {
122        return buf;
123    }
124
125
126    /**
127     * Get's a copy of the bytes used.
128     * 
129     * @return A copy of the interned Byte[]
130     */
131    public final byte[] copyOfUsedBytes()
132    {
133        byte[] copy = new byte[pos];
134        System.arraycopy( buf, 0, copy, 0, pos );
135        return copy;
136    }
137
138
139    /**
140     * Appends the bytes to this buffer.
141     * 
142     * @param bytes The byte[] to append to the buffer
143     */
144    public final void append( byte[] bytes )
145    {
146        if ( pos + bytes.length > buf.length )
147        {
148            growBuffer( bytes.length );
149        }
150
151        System.arraycopy( bytes, 0, buf, pos, bytes.length );
152        pos += bytes.length;
153    }
154
155
156    /**
157     * Appends a byte to this buffer.
158     * 
159     * @param b The byte to append to the buffer
160     */
161    public final void append( byte b )
162    {
163        if ( pos >= buf.length )
164        {
165            growBuffer();
166        }
167
168        buf[pos] = b;
169        pos++;
170    }
171
172
173    /**
174     * Appends an int to this buffer.  WARNING: the int is truncated to 
175     * a byte value.
176     * 
177     * @param val The integer to append to the buffer
178     */
179    public final void append( int val )
180    {
181        if ( pos >= buf.length )
182        {
183            growBuffer();
184        }
185
186        buf[pos] = ( byte ) val;
187        pos++;
188    }
189
190
191    private void growBuffer( int size )
192    {
193        if ( size > initialSize )
194        {
195            byte[] copy = new byte[buf.length + size];
196            System.arraycopy( buf, 0, copy, 0, pos );
197            this.buf = copy;
198        }
199        else
200        {
201            byte[] copy = new byte[buf.length + initialSize];
202            System.arraycopy( buf, 0, copy, 0, pos );
203            this.buf = copy;
204        }
205    }
206
207
208    private void growBuffer()
209    {
210        byte[] copy = new byte[buf.length + initialSize];
211        System.arraycopy( buf, 0, copy, 0, pos );
212        this.buf = copy;
213    }
214}