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    public ByteBuffer()
047    {
048        this( DEFAULT_INITIAL_SIZE );
049    }
050
051
052    public ByteBuffer( int initialSize )
053    {
054        if ( initialSize <= 0 )
055        {
056            throw new IllegalArgumentException( I18n.err( I18n.ERR_04354 ) );
057        }
058
059        this.initialSize = initialSize;
060        this.buf = new byte[initialSize];
061    }
062
063
064    public final void clear()
065    {
066        pos = 0;
067    }
068
069
070    public final int position()
071    {
072        return pos;
073    }
074
075
076    public final int capacity()
077    {
078        return buf.length;
079    }
080
081
082    public final byte get( int i )
083    {
084        return buf[i];
085    }
086
087
088    /**
089     * Get's the bytes, the backing store for this buffer.  Note
090     * that you need to use the position index to determine where
091     * to stop reading from this buffer.
092     */
093    public final byte[] buffer()
094    {
095        return buf;
096    }
097
098
099    /**
100     * Get's a copy of the bytes used.
101     */
102    public final byte[] copyOfUsedBytes()
103    {
104        byte[] copy = new byte[pos];
105        System.arraycopy( buf, 0, copy, 0, pos );
106        return copy;
107    }
108
109
110    /**
111     * Appends the bytes to this buffer.
112     */
113    public final void append( byte[] bytes )
114    {
115        if ( pos + bytes.length > buf.length )
116        {
117            growBuffer( bytes.length );
118        }
119
120        System.arraycopy( bytes, 0, buf, pos, bytes.length );
121        pos += bytes.length;
122    }
123
124
125    /**
126     * Appends a byte to this buffer.
127     */
128    public final void append( byte b )
129    {
130        if ( pos >= buf.length )
131        {
132            growBuffer();
133        }
134
135        buf[pos] = b;
136        pos++;
137    }
138
139
140    /**
141     * Appends an int to this buffer.  WARNING: the int is truncated to 
142     * a byte value.
143     */
144    public final void append( int val )
145    {
146        if ( pos >= buf.length )
147        {
148            growBuffer();
149        }
150
151        buf[pos] = ( byte ) val;
152        pos++;
153    }
154
155
156    private void growBuffer( int size )
157    {
158        if ( size > initialSize )
159        {
160            byte[] copy = new byte[buf.length + size];
161            System.arraycopy( buf, 0, copy, 0, pos );
162            this.buf = copy;
163        }
164        else
165        {
166            byte[] copy = new byte[buf.length + initialSize];
167            System.arraycopy( buf, 0, copy, 0, pos );
168            this.buf = copy;
169        }
170    }
171
172
173    private void growBuffer()
174    {
175        byte[] copy = new byte[buf.length + initialSize];
176        System.arraycopy( buf, 0, copy, 0, pos );
177        this.buf = copy;
178    }
179}