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.james.mime4j.util;
021
022
023/**
024 * A resizable byte array.
025 */
026public final class ByteArrayBuffer implements ByteSequence {
027
028    private byte[] buffer;
029    private int len;
030
031    public ByteArrayBuffer(int capacity) {
032        super();
033        if (capacity < 0) {
034            throw new IllegalArgumentException("Buffer capacity may not be negative");
035        }
036        this.buffer = new byte[capacity];
037    }
038
039    public ByteArrayBuffer(byte[] bytes, boolean dontCopy) {
040        this(bytes, bytes.length, dontCopy);
041    }
042
043    public ByteArrayBuffer(byte[] bytes, int len, boolean dontCopy) {
044        if (bytes == null)
045            throw new IllegalArgumentException();
046        if (len < 0 || len > bytes.length)
047            throw new IllegalArgumentException();
048
049        if (dontCopy) {
050            this.buffer = bytes;
051        } else {
052            this.buffer = new byte[len];
053            System.arraycopy(bytes, 0, this.buffer, 0, len);
054        }
055
056        this.len = len;
057    }
058
059    private void expand(int newlen) {
060        byte newbuffer[] = new byte[Math.max(this.buffer.length << 1, newlen)];
061        System.arraycopy(this.buffer, 0, newbuffer, 0, this.len);
062        this.buffer = newbuffer;
063    }
064
065    public void append(final byte[] b, int off, int len) {
066        if (b == null) {
067            return;
068        }
069        if ((off < 0) || (off > b.length) || (len < 0) ||
070                ((off + len) < 0) || ((off + len) > b.length)) {
071            throw new IndexOutOfBoundsException();
072        }
073        if (len == 0) {
074            return;
075        }
076        int newlen = this.len + len;
077        if (newlen > this.buffer.length) {
078            expand(newlen);
079        }
080        System.arraycopy(b, off, this.buffer, this.len, len);
081        this.len = newlen;
082    }
083
084    public void append(int b) {
085        int newlen = this.len + 1;
086        if (newlen > this.buffer.length) {
087            expand(newlen);
088        }
089        this.buffer[this.len] = (byte)b;
090        this.len = newlen;
091    }
092
093    public void clear() {
094        this.len = 0;
095    }
096
097    public byte[] toByteArray() {
098        byte[] b = new byte[this.len];
099        if (this.len > 0) {
100            System.arraycopy(this.buffer, 0, b, 0, this.len);
101        }
102        return b;
103    }
104
105    public byte byteAt(int i) {
106        if (i < 0 || i >= this.len)
107            throw new IndexOutOfBoundsException();
108
109        return this.buffer[i];
110    }
111
112    public int capacity() {
113        return this.buffer.length;
114    }
115
116    public int length() {
117        return this.len;
118    }
119
120    public byte[] buffer() {
121        return this.buffer;
122    }
123
124    public int indexOf(byte b) {
125        return indexOf(b, 0, this.len);
126    }
127
128    public int indexOf(byte b, int beginIndex, int endIndex) {
129        if (beginIndex < 0) {
130            beginIndex = 0;
131        }
132        if (endIndex > this.len) {
133            endIndex = this.len;
134        }
135        if (beginIndex > endIndex) {
136            return -1;
137        }
138        for (int i = beginIndex; i < endIndex; i++) {
139            if (this.buffer[i] == b) {
140                return i;
141            }
142        }
143        return -1;
144    }
145
146    public void setLength(int len) {
147        if (len < 0 || len > this.buffer.length) {
148            throw new IndexOutOfBoundsException();
149        }
150        this.len = len;
151    }
152
153    public void remove(int off, int len) {
154        if ((off < 0) || (off > this.len) || (len < 0) ||
155                ((off + len) < 0) || ((off + len) > this.len)) {
156            throw new IndexOutOfBoundsException();
157        }
158        if (len == 0) {
159            return;
160        }
161        int remaining = this.len - off - len;
162        if (remaining > 0) {
163            System.arraycopy(this.buffer, off + len, this.buffer, off, remaining);
164        }
165        this.len -= len;
166    }
167
168    public boolean isEmpty() {
169        return this.len == 0;
170    }
171
172    public boolean isFull() {
173        return this.len == this.buffer.length;
174    }
175
176    @Override
177    public String toString() {
178        return new String(toByteArray());
179    }
180
181}