001    /*
002     * Copyright (c) Andrey Kuznetsov. All Rights Reserved.
003     *
004     * http://uio.imagero.com
005     *
006     * Redistribution and use in source and binary forms, with or without
007     * modification, are permitted provided that the following conditions are met:
008     *
009     *  o Redistributions of source code must retain the above copyright notice,
010     *    this list of conditions and the following disclaimer.
011     *
012     *  o Redistributions in binary form must reproduce the above copyright notice,
013     *    this list of conditions and the following disclaimer in the documentation
014     *    and/or other materials provided with the distribution.
015     *
016     *  o Neither the name of Andrey Kuznetsov nor the names of
017     *    its contributors may be used to endorse or promote products derived
018     *    from this software without specific prior written permission.
019     *
020     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
021     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
022     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
023     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
027     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
028     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
029     * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
030     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031     */
032    package com.imagero.uio.bio;
033    
034    import java.io.DataOutput;
035    import java.io.IOException;
036    import java.io.InputStream;
037    import java.io.OutputStream;
038    
039    /**
040     * This class can be used to read from and write to byte array.
041     *
042     * @author Andrey Kuznetsov
043     */
044    public class VariableSizeByteBuffer {
045    
046        private Buffer buf;
047        int count;
048    
049        boolean changed;
050    
051        public VariableSizeByteBuffer(int size) {
052            this(new byte[size]);
053        }
054    
055        public VariableSizeByteBuffer(byte buf[]) {
056            this(new Buffer(buf));
057        }
058    
059        public VariableSizeByteBuffer(Buffer buf) {
060            this.buf = buf;
061        }
062    
063        public VariableSizeByteBuffer create() {
064            return new VariableSizeByteBuffer(buf);
065        }
066    
067        public void seek(int pos, BufferPosition position) {
068            position.pos = pos;
069        }
070    
071        public int read(BufferPosition position) {
072            if (position.pos > count) {
073                return -1;
074            }
075            return buf.buffer[position.pos++] & 0xFF;
076        }
077    
078        public long skip(long n, BufferPosition position) {
079            long p = Math.max(0L, Math.min(n, Integer.MAX_VALUE));
080            position.pos += p;
081            return p;
082        }
083    
084        /**
085         * get amount of bytes which may be written without changing buffer size
086         */
087        public int availableForWriting(BufferPosition position) {
088            return buf.buffer.length - position.pos;
089        }
090    
091        public int availableForReading(BufferPosition position) {
092            return Math.max(0, count - position.pos);
093        }
094    
095        public int read(byte[] dest, int offset, int length, BufferPosition position) {
096            final int available = availableForReading(position);
097            int toRead = Math.max(0, Math.min(length, available));
098            if (toRead > 0) {
099                System.arraycopy(buf.buffer, position.pos, dest, offset, toRead);
100                position.pos += toRead;
101            }
102            return toRead;
103        }
104    
105        public int read(short[] dest, int offset, int length, boolean bigEndian, BufferPosition position) {
106            final int available = availableForReading(position) >> 1;
107            int toRead = Math.max(0, Math.min(length, available));
108            com.imagero.uio.Transformer.byteToShort(buf.buffer, position.pos, toRead, dest, offset, bigEndian);
109            position.pos += toRead << 1;
110            return toRead;
111        }
112    
113        public int read(char[] dest, int offset, int length, boolean bigEndian, BufferPosition position) {
114            final int available = availableForReading(position) >> 1;
115            int toRead = Math.max(0, Math.min(length, available));
116            com.imagero.uio.Transformer.byteToChar(buf.buffer, position.pos, toRead, dest, offset, bigEndian);
117            position.pos += toRead << 1;
118            return toRead;
119        }
120    
121        public int read(int[] dest, int offset, int length, boolean bigEndian, BufferPosition position) {
122            final int available = availableForReading(position) >> 2;
123            int toRead = Math.max(0, Math.min(length, available));
124            com.imagero.uio.Transformer.byteToInt(buf.buffer, position.pos, toRead, dest, offset, bigEndian);
125            position.pos += toRead << 2;
126            return toRead;
127        }
128    
129        public int read(float[] dest, int offset, int length, boolean bigEndian, BufferPosition position) {
130            final int available = availableForReading(position) >> 2;
131            int toRead = Math.max(0, Math.min(length, available));
132            com.imagero.uio.Transformer.byteToFloat(buf.buffer, position.pos, toRead, dest, offset, bigEndian);
133            position.pos += toRead << 2;
134            return toRead;
135        }
136    
137        public int read(long[] dest, int offset, int length, boolean bigEndian, BufferPosition position) {
138            final int available = availableForReading(position) >> 3;
139            int toRead = Math.max(0, Math.min(length, available));
140            com.imagero.uio.Transformer.byteToLong(buf.buffer, position.pos, toRead, dest, offset, bigEndian);
141            position.pos += toRead << 3;
142            return toRead;
143        }
144    
145        public int read(double[] dest, int offset, int length, boolean bigEndian, BufferPosition position) {
146            final int available = availableForReading(position) >> 3;
147            int toRead = Math.max(0, Math.min(length, available));
148            com.imagero.uio.Transformer.byteToDouble(buf.buffer, position.pos, toRead, dest, offset, bigEndian);
149            position.pos += toRead << 3;
150            return toRead;
151        }
152    
153        public int getCount() {
154            return count;
155        }
156    
157        public void setCount(int count) {
158            this.count = Math.min(Math.max(count, 0), buf.buffer.length);
159        }
160    
161        public void writeBuffer(OutputStream out) throws IOException {
162            out.write(buf.buffer, 0, count);
163        }
164    
165        public void writeBuffer(DataOutput out) throws IOException {
166            out.write(buf.buffer, 0, count);
167        }
168    
169        public void write(byte b[], int offset, int length, BufferPosition position) {
170            if (length > 0) {
171                checkSize(length, position);
172                System.arraycopy(b, offset, buf.buffer, position.pos, length);
173                position.pos += length;
174                count = Math.max(count, position.pos);
175            }
176        }
177    
178        public void write(short[] src, int offset, int length, boolean bigEndian, BufferPosition position) {
179            int len1 = length << 1;
180            checkSize(len1, position);
181            com.imagero.uio.Transformer.shortToByte(src, offset, length, buf.buffer, position.pos, bigEndian);
182            position.pos += len1;
183            count = Math.max(count, position.pos);
184        }
185    
186        public void write(char[] src, int offset, int length, boolean bigEndian, BufferPosition position) {
187            int len1 = length << 1;
188            checkSize(len1, position);
189            com.imagero.uio.Transformer.charToByte(src, offset, length, buf.buffer, position.pos, bigEndian);
190            position.pos += len1;
191            count = Math.max(count, position.pos);
192        }
193    
194        public void write(int[] src, int offset, int length, boolean bigEndian, BufferPosition position) {
195            final int len2 = length << 2;
196            checkSize(len2, position);
197            com.imagero.uio.Transformer.intToByte(src, offset, length, buf.buffer, position.pos, bigEndian);
198            position.pos += len2;
199            count = Math.max(count, position.pos);
200        }
201    
202        public void write(float[] src, int offset, int length, boolean bigEndian, BufferPosition position) {
203            final int len2 = length << 2;
204            checkSize(len2, position);
205            com.imagero.uio.Transformer.floatToByte(src, offset, length, buf.buffer, position.pos, bigEndian);
206            position.pos += len2;
207            count = Math.max(count, position.pos);
208        }
209    
210        public void write(long[] src, int offset, int length, boolean bigEndian, BufferPosition position) {
211            final int len3 = length << 3;
212            checkSize(len3, position);
213            com.imagero.uio.Transformer.longToByte(src, offset, length, buf.buffer, position.pos, bigEndian);
214            position.pos += length << 3;
215            count = Math.max(count, position.pos);
216        }
217    
218        public void write(double[] src, int offset, int length, boolean bigEndian, BufferPosition position) {
219            final int len3 = length << 3;
220            checkSize(len3, position);
221            com.imagero.uio.Transformer.doubleToByte(src, offset, length, buf.buffer, position.pos, bigEndian);
222            position.pos += len3;
223            count = Math.max(count, position.pos);
224        }
225    
226        public void write(int b, BufferPosition position) {
227            checkSize(1, position);
228            buf.buffer[position.pos++] = (byte) b;
229            count = Math.max(count, position.pos);
230        }
231    
232        private synchronized void checkSize(int k, BufferPosition position) {
233            if (position.pos + k > buf.buffer.length) {
234                byte newbuf[] = new byte[Math.max(buf.buffer.length << 1, position.pos + k)];
235                System.arraycopy(buf.buffer, 0, newbuf, 0, count);
236                buf.buffer = newbuf;
237            }
238        }
239    
240        public InputStream getInputStream(int offset) {
241            return new VSBInputStream(offset, this);
242        }
243    
244        public OutputStream getOutputStream(int offset) {
245            return new VSBOutputStream(offset, this);
246        }
247    
248        static class VSBInputStream extends InputStream {
249            VariableSizeByteBuffer buffer;
250            BufferPosition position;
251            int mark;
252    
253            public VSBInputStream(VariableSizeByteBuffer buffer) {
254                this.buffer = buffer;
255                position = new BufferPosition(Integer.MAX_VALUE);
256            }
257    
258            public VSBInputStream(int offset, VariableSizeByteBuffer buffer) {
259                this.buffer = buffer;
260                position = new BufferPosition(Integer.MAX_VALUE);
261                buffer.seek(offset, position);
262            }
263    
264            public int read() {
265                return buffer.read(position);
266            }
267    
268            public int read(byte b[]) throws IOException {
269                return buffer.read(b, 0, b.length, position);
270            }
271    
272            public int read(byte b[], int off, int len) {
273                return buffer.read(b, off, len, position);
274            }
275    
276            public long skip(long n) {
277                return buffer.skip(n, position);
278            }
279    
280            public int available() {
281                return buffer.availableForReading(position);
282            }
283    
284            public synchronized void mark(int readlimit) {
285                this.mark = position.pos;
286            }
287    
288            public synchronized void reset() throws IOException {
289                buffer.seek(mark, position);
290            }
291    
292            public boolean markSupported() {
293                return true;
294            }
295        }
296    
297        static class VSBOutputStream extends OutputStream {
298            VariableSizeByteBuffer buffer;
299            BufferPosition position;
300    
301            public VSBOutputStream(VariableSizeByteBuffer buffer) {
302                this(0, buffer);
303            }
304    
305            public VSBOutputStream(int offset, VariableSizeByteBuffer buffer) {
306                this.buffer = buffer;
307                position = new BufferPosition(Integer.MAX_VALUE);
308                buffer.seek(offset, position);
309            }
310    
311            public void write(int b) throws IOException {
312                buffer.write(b, position);
313            }
314    
315            public void write(byte b[]) throws IOException {
316                buffer.write(b, 0, b.length, position);
317            }
318    
319            public void write(byte b[], int off, int len) throws IOException {
320                buffer.write(b, off, len, position);
321            }
322    
323            public void close() throws IOException {
324                buffer = null;
325            }
326        }
327    }