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 }