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    /*
033     * Copyright (c) Andrey Kuznetsov. All Rights Reserved.
034     *
035     * http://uio.imagero.com
036     *
037     * Redistribution and use in source and binary forms, with or without
038     * modification, are permitted provided that the following conditions are met:
039     *
040     *  o Redistributions of source code must retain the above copyright notice,
041     *    this list of conditions and the following disclaimer.
042     *
043     *  o Redistributions in binary form must reproduce the above copyright notice,
044     *    this list of conditions and the following disclaimer in the documentation
045     *    and/or other materials provided with the distribution.
046     *
047     *  o Neither the name of Andrey Kuznetsov nor the names of
048     *    its contributors may be used to endorse or promote products derived
049     *    from this software without specific prior written permission.
050     *
051     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
052     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
053     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
054     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
055     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
056     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
057     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
058     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
059     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
060     * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
061     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
062     */
063    package com.imagero.uio.bio;
064    
065    import com.imagero.uio.Transformer;
066    import com.imagero.uio.RandomAccessIO;
067    import com.imagero.uio.RandomAccessInput;
068    import com.imagero.uio.RandomAccessOutput;
069    import com.imagero.uio.impl.AbstractRandomAccessIO;
070    
071    import java.io.DataOutput;
072    import java.io.IOException;
073    import java.io.OutputStream;
074    import java.io.InputStream;
075    
076    /**
077     * This class can be used to read from and write to byte array.
078     *
079     * @author Andrey Kuznetsov
080     */
081    public class FixedSizeByteBuffer {
082    
083        byte[] buf;
084        int count;
085    
086        boolean changed;
087        BufferIndex index;
088    
089        public FixedSizeByteBuffer(byte buf[]) {
090            this.buf = buf;
091        }
092    
093        public int read(BufferPosition position) {
094            if (availableForReading(position) > 0) {
095                int v = buf[position.pos++] & 0xFF;
096                return v;
097            }
098            return -1;
099        }
100    
101        public long skip(long n, BufferPosition position) {
102            long p = Math.max(0, Math.min(count - position.pos, n));
103            position.pos += p;
104            return p;
105        }
106    
107        public int availableForReading(BufferPosition position) {
108            return Math.max(0, count - position.pos);
109        }
110    
111        public int availableForWriting(BufferPosition position) {
112            return Math.max(0, buf.length - position.pos);
113        }
114    
115        public int read(byte[] dest, int offset, int length, BufferPosition position) {
116            final int available = availableForReading(position);
117            int toCopy = Math.max(0, Math.min(length, available));
118            if (toCopy > 0) {
119                System.arraycopy(buf, position.pos, dest, offset, toCopy);
120                position.pos += toCopy;
121            }
122            return toCopy;
123        }
124    
125        public int read(short[] dest, int offset, int length, boolean bigEndian, BufferPosition position) {
126            final int available = availableForReading(position) >> 1;
127            int toCopy = Math.max(0, Math.min(length, available));
128            com.imagero.uio.Transformer.byteToShort(buf, position.pos, toCopy, dest, offset, bigEndian);
129            position.pos += toCopy << 1;
130            return toCopy;
131        }
132    
133        public int read(char[] dest, int offset, int length, boolean bigEndian, BufferPosition position) {
134            final int available = availableForReading(position) >> 1;
135            int toCopy = Math.max(0, Math.min(length, available));
136            com.imagero.uio.Transformer.byteToChar(buf, position.pos, toCopy, dest, offset, bigEndian);
137            position.pos += toCopy << 1;
138            return toCopy;
139        }
140    
141        public int read(int[] dest, int offset, int length, boolean bigEndian, BufferPosition position) {
142            final int available = availableForReading(position) >> 2;
143            int toCopy = Math.max(0, Math.min(length, available));
144            com.imagero.uio.Transformer.byteToInt(buf, position.pos, toCopy, dest, offset, bigEndian);
145            position.pos += toCopy << 2;
146            return toCopy;
147        }
148    
149        public int read(float[] dest, int offset, int length, boolean bigEndian, BufferPosition position) {
150            final int available = availableForReading(position) >> 2;
151            int toCopy = Math.max(0, Math.min(length, available));
152            com.imagero.uio.Transformer.byteToFloat(buf, position.pos, toCopy, dest, offset, bigEndian);
153            position.pos += toCopy << 2;
154            return toCopy;
155        }
156    
157        public int read(long[] dest, int offset, int length, boolean bigEndian, BufferPosition position) {
158            final int available = availableForReading(position) >> 3;
159            int toCopy = Math.max(0, Math.min(length, available));
160            com.imagero.uio.Transformer.byteToLong(buf, position.pos, toCopy, dest, offset, bigEndian);
161            position.pos += toCopy << 3;
162            return toCopy;
163        }
164    
165        public int read(double[] dest, int offset, int length, boolean bigEndian, BufferPosition position) {
166            final int available = availableForReading(position) >> 3;
167            int toCopy = Math.max(0, Math.min(length, available));
168            com.imagero.uio.Transformer.byteToDouble(buf, position.pos, toCopy, dest, offset, bigEndian);
169            position.pos += toCopy << 3;
170            return toCopy;
171        }
172    
173        /**
174         * write given byte to buffer.
175         *
176         * @param b int to write
177         */
178        public void write(int b, BufferPosition position) {
179            buf[position.pos++] = (byte) b;
180            count = Math.max(position.pos, count);
181        }
182    
183        public int getCount() {
184            return count;
185        }
186    
187        public int getPosition(BufferPosition position) {
188            return position.pos;
189        }
190    
191        public void setCount(int count) {
192            this.count = Math.min(Math.max(count, 0), buf.length);
193        }
194    
195        /**
196         * write buffer contents to OutputStream
197         * @param wholeBuffer if true then whole buffer is written, otherwise only getCount() bytes are written
198         */
199        public void writeBuffer(OutputStream out, boolean wholeBuffer) throws IOException {
200            if (wholeBuffer) {
201                out.write(buf);
202            } else {
203                out.write(buf, 0, count);
204            }
205        }
206    
207        public void writeBuffer(DataOutput out, boolean wholeBuffer) throws IOException {
208            if (wholeBuffer) {
209                out.write(buf);
210            } else {
211                out.write(buf, 0, count);
212            }
213        }
214    
215        /**
216         * write whole buffer contents to OutputStream (count is ignored)
217         */
218        public void writeBuffer(OutputStream out) throws IOException {
219            out.write(buf);
220        }
221    
222        public void writeBuffer(DataOutput out) throws IOException {
223            out.write(buf);
224        }
225    
226        public int write(byte src[], int offset, int length, BufferPosition position) {
227            int available = availableForWriting(position);
228            int toCopy = Math.max(0, Math.min(length, available));
229            if (toCopy > 0) {
230                System.arraycopy(src, offset, buf, position.pos, toCopy);
231                position.pos += toCopy;
232                count = Math.max(count, position.pos);
233            }
234            return toCopy;
235        }
236    
237        public int write(short[] src, int offset, int length, boolean bigEndian, BufferPosition position) {
238            final int available = availableForWriting(position) >> 1;
239            int toCopy = Math.max(0, Math.min(length, available));
240            com.imagero.uio.Transformer.shortToByte(src, offset, toCopy, buf, position.pos, bigEndian);
241            position.pos += toCopy << 1;
242            count = Math.max(count, position.pos);
243            return toCopy;
244        }
245    
246        public int write(char[] src, int offset, int length, boolean bigEndian, BufferPosition position) {
247            final int available = availableForWriting(position) >> 1;
248            int toCopy = Math.max(0, Math.min(length, available));
249            com.imagero.uio.Transformer.charToByte(src, offset, toCopy, buf, position.pos, bigEndian);
250            position.pos += toCopy << 1;
251            count = Math.max(count, position.pos);
252            return toCopy;
253        }
254    
255        public int write(int[] src, int offset, int length, boolean bigEndian, BufferPosition position) {
256            final int available = availableForWriting(position) >> 2;
257            int toCopy = Math.max(0, Math.min(length, available));
258            com.imagero.uio.Transformer.intToByte(src, offset, toCopy, buf, position.pos, bigEndian);
259            position.pos += toCopy << 2;
260            count = Math.max(count, position.pos);
261            return toCopy;
262        }
263    
264        public int write(float[] src, int offset, int length, boolean bigEndian, BufferPosition position) {
265            final int available = availableForWriting(position) >> 2;
266            int toCopy = Math.max(0, Math.min(length, available));
267            com.imagero.uio.Transformer.floatToByte(src, offset, toCopy, buf, position.pos, bigEndian);
268            position.pos += toCopy << 2;
269            count = Math.max(count, position.pos);
270            return toCopy;
271        }
272    
273        public int write(long[] src, int offset, int length, boolean bigEndian, BufferPosition position) {
274            final int available = availableForWriting(position) >> 3;
275            int toCopy = Math.max(0, Math.min(length, available));
276            com.imagero.uio.Transformer.longToByte(src, offset, toCopy, buf, position.pos, bigEndian);
277            position.pos += toCopy << 3;
278            count = Math.max(count, position.pos);
279            return toCopy;
280        }
281    
282        public int write(double[] src, int offset, int length, boolean bigEndian, BufferPosition position) {
283            final int available = availableForWriting(position) >> 3;
284            int toCopy = Math.max(0, Math.min(length, available));
285            com.imagero.uio.Transformer.doubleToByte(src, offset, toCopy, buf, position.pos, bigEndian);
286            position.pos += toCopy << 3;
287            count = Math.max(count, position.pos);
288            return toCopy;
289        }
290    
291        public RandomAccessIO create() {
292            return new FSBRandomAccessIO(this);
293        }
294    
295        public RandomAccessIO create(int offset, int length) {
296            return new FSBRandomAccessIO(this, offset, length);
297        }
298    
299        static class FSBRandomAccessIO extends AbstractRandomAccessIO {
300    
301            FixedSizeByteBuffer buffer;
302            BufferPosition position;
303    
304            int offset;
305            int length;
306    
307            public FSBRandomAccessIO(FixedSizeByteBuffer buffer) {
308                this(buffer, 0, buffer.buf.length);
309            }
310    
311            public FSBRandomAccessIO(FixedSizeByteBuffer buffer, int offset) {
312                this(buffer, offset, buffer.buf.length - offset);
313            }
314    
315            public FSBRandomAccessIO(FixedSizeByteBuffer buffer, int offset, int length) {
316                this.buffer = buffer;
317                this.offset = offset;
318                this.length = length;
319            }
320    
321            public int read() throws IOException {
322                return buffer.read(position);
323            }
324    
325            public void seek(long pos) {
326                position.pos = (int) Math.min(length, pos + offset);
327            }
328    
329            public long length() throws IOException {
330                return length;
331            }
332    
333            public long getFilePointer() throws IOException {
334                return position.pos - offset;
335            }
336    
337            public void setLength(long newLength) throws IOException {
338                this.length = (int) Math.min(buffer.buf.length, newLength);
339            }
340    
341            public void write(int b) throws IOException {
342                buffer.write(b, position);
343            }
344    
345            public void write(byte b[], int off, int len) throws IOException {
346                buffer.write(b, off, len, position);
347            }
348    
349            public InputStream createInputStream(long offset) {
350                return new FSBInputStream((int) offset, buffer);
351            }
352    
353            public OutputStream createOutputStream(long offset) {
354                return new FSBOutputStream((int) offset, buffer) ;
355            }
356    
357            public RandomAccessIO createIOChild(long offset, int byteOrder, boolean syncPointer) throws IOException {
358                FSBRandomAccessIO rio = new FSBRandomAccessIO(buffer, (int) offset);
359                if(syncPointer) {
360                    rio.position = position;
361                }
362                rio.setByteOrder(byteOrder);
363                return rio;
364            }
365    
366            public RandomAccessInput createInputChild(long offset, int byteOrder, boolean syncPointer) throws IOException {
367                return createIOChild(offset, byteOrder, syncPointer);
368            }
369    
370            public RandomAccessOutput createOutputChild(long offset, int byteOrder, boolean syncPointer) throws IOException {
371                return createIOChild(offset, byteOrder, syncPointer);
372            }
373        }
374    
375        static class FSBInputStream extends InputStream {
376            FixedSizeByteBuffer buffer;
377            BufferPosition position;
378            int mark;
379    
380            public FSBInputStream(FixedSizeByteBuffer buffer) {
381                this.buffer = buffer;
382                position = new BufferPosition(buffer.buf.length);
383            }
384    
385            public FSBInputStream(int offset, FixedSizeByteBuffer buffer) {
386                this.buffer = buffer;
387                position = new BufferPosition(Integer.MAX_VALUE);
388                position.pos = offset;
389            }
390    
391            public int read() {
392                return buffer.read(position);
393            }
394    
395            public int read(byte b[]) throws IOException {
396                return buffer.read(b, 0, b.length, position);
397            }
398    
399            public int read(byte b[], int off, int len) {
400                return buffer.read(b, off, len, position);
401            }
402    
403            public long skip(long n) {
404                return buffer.skip(n, position);
405            }
406    
407            public int available() {
408                return buffer.availableForReading(position);
409            }
410    
411            public synchronized void mark(int readlimit) {
412                this.mark = position.pos;
413            }
414    
415            public synchronized void reset() throws IOException {
416                position.pos = mark;
417            }
418    
419            public boolean markSupported() {
420                return true;
421            }
422        }
423    
424        static class FSBOutputStream extends OutputStream {
425            FixedSizeByteBuffer buffer;
426            BufferPosition position;
427    
428            public FSBOutputStream(FixedSizeByteBuffer buffer) {
429                this(0, buffer);
430            }
431    
432            public FSBOutputStream(int offset, FixedSizeByteBuffer buffer) {
433                this.buffer = buffer;
434                position = new BufferPosition(Integer.MAX_VALUE);
435                position.pos = offset;
436            }
437    
438            public void write(int b) throws IOException {
439                buffer.write(b, position);
440            }
441    
442            public void write(byte b[]) throws IOException {
443                buffer.write(b, 0, b.length, position);
444            }
445    
446            public void write(byte b[], int off, int len) throws IOException {
447                buffer.write(b, off, len, position);
448            }
449    
450            public void close() throws IOException {
451                buffer = null;
452            }
453        }
454    }