1 /*******************************************************************************
2 * Copyright (c) 2010, 2016 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.databoard.util.binary;
14 import java.io.DataInputStream;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.nio.ByteBuffer;
20 * Rancom access memory blob
22 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
24 public class BinaryMemory implements RandomAccessBinary {
28 /** the number of bytes added spare to the buffer when it is incremented */
34 public BinaryMemory() {
35 buf = ByteBuffer.allocate(16);
42 public BinaryMemory(byte[] data) {
43 this.buf = ByteBuffer.wrap(data);
49 public BinaryMemory(byte[] data, int offset, int length) {
50 this.buf = ByteBuffer.wrap(data, offset, length);
56 public BinaryMemory(int initialSize) {
57 buf = ByteBuffer.allocate(initialSize);
58 increment = Math.max(16, initialSize);
64 public BinaryMemory(int initialSize, int increment) {
65 buf = ByteBuffer.allocate(initialSize);
66 this.increment = increment;
70 * Assume an existing byte buffer
74 public BinaryMemory(ByteBuffer buf) {
79 * Get the backend byte buffer. The result may change if BinaryMemory is
84 public ByteBuffer toByteBuffer() {
89 public void close() throws IOException {
93 public boolean isOpen() {
98 public void flush() throws IOException {
102 public void reset() throws IOException {
106 public byte readByte() {
107 assertHasReadableBytes(1);
108 buf.position( (int) pointer );
109 byte result = buf.get();
115 if (pointer >= buf.limit()) return -1;
116 buf.position( (int) pointer );
117 byte result = buf.get();
119 return result & 0xff;
122 public final String readLine() throws IOException {
123 StringBuffer input = new StringBuffer();
128 switch (c = _read()) {
135 long cur = position();
136 if ((_read()) != '\n') {
141 input.append((char)c);
146 if ((c == -1) && (input.length() == 0)) {
149 return input.toString();
152 public final String readUTF() throws IOException {
153 return DataInputStream.readUTF(this);
157 public int readUnsignedByte() throws IOException {
158 return readByte() & 0x000000ff;
162 public boolean readBoolean() throws IOException {
163 assertHasReadableBytes(1);
164 buf.position( (int) pointer );
165 byte result = buf.get();
171 public void readFully(byte[] dst, int offset, int length) {
172 assertHasReadableBytes(length);
173 buf.position( (int) pointer );
174 buf.get(dst, offset, length);
179 public void readFully(byte[] dst) {
180 assertHasReadableBytes(dst.length);
181 buf.position( (int) pointer );
183 pointer += dst.length;
187 public void readFully(ByteBuffer buf) {
188 int bytes = buf.remaining();
189 assertHasReadableBytes( bytes );
190 buf.position( (int) pointer );
191 if (buf.hasArray()) {
192 this.buf.get(buf.array(), buf.arrayOffset() + buf.position(), bytes);
193 buf.position(buf.capacity());
201 public void readFully(ByteBuffer buf, int length) {
202 assertHasReadableBytes(length);
203 buf.position( (int) pointer );
204 if (buf.hasArray()) {
205 this.buf.get(buf.array(), buf.arrayOffset() + buf.position(), length);
206 buf.position(buf.position() + length);
208 // int len = Math.min( Math.min( buf.remaining(), this.buf.remaining() ), length);
210 int origLimit = this.buf.limit();
212 this.buf.limit(this.buf.position()+len);
215 this.buf.limit(origLimit);
222 public double readDouble() {
223 assertHasReadableBytes(8);
224 buf.position( (int) pointer );
225 double value = buf.getDouble();
231 public float readFloat() {
232 assertHasReadableBytes(4);
233 buf.position( (int) pointer );
234 float result = buf.getFloat();
240 public int readInt() {
241 assertHasReadableBytes(4);
242 buf.position( (int) pointer );
243 int value = buf.getInt();
249 public long readLong() {
250 assertHasReadableBytes(8);
251 buf.position( (int) pointer );
252 long value = buf.getLong();
258 public short readShort() {
259 assertHasReadableBytes(2);
260 buf.position( (int) pointer );
261 short result = buf.getShort();
267 public char readChar() {
268 assertHasReadableBytes(2);
269 buf.position( (int) pointer );
270 char result = buf.getChar();
276 public int readUnsignedShort() {
277 assertHasReadableBytes(2);
278 buf.position( (int) pointer );
279 int result = buf.getShort() & 0xffff;
285 public long length() {
290 public long position() {
295 public void position(long newPosition) throws IOException {
296 this.pointer = newPosition;
300 public void write(int b) throws IOException {
301 assertHasWritableBytes(1);
302 buf.position( (int) pointer );
308 public void writeByte(int b) throws IOException {
309 assertHasWritableBytes(1);
310 buf.position( (int) pointer );
316 public void writeBoolean(boolean v) throws IOException {
317 assertHasWritableBytes(1);
318 buf.position( (int) pointer );
319 buf.put( (byte) (v ? 1 : 0) );
324 public void writeFully(ByteBuffer src) throws IOException {
325 long bytes = src.remaining();
326 assertHasWritableBytes( bytes );
327 buf.position( (int) pointer );
333 public void writeFully(ByteBuffer src, int length) throws IOException {
334 assertHasWritableBytes(length);
335 buf.position( (int) pointer );
336 if (src.hasArray()) {
337 byte[] array = src.array();
338 buf.put(array, src.arrayOffset() + src.position(), length);
340 for (int i=0; i<length; i++)
347 public void put(InputStream is) throws IOException {
348 long oldLen = length();
349 while (is.available()>0) {
350 int n = is.available();
351 assertHasWritableBytes(n);
352 byte buf[] = this.buf.array();
353 n = is.read(buf, (int) pointer, n);
356 long newLen = length();
357 if (newLen>oldLen & pointer<newLen) setLength(pointer);
361 public void write(byte[] src, int offset, int length) throws IOException {
362 assertHasWritableBytes(length);
363 buf.position( (int) pointer );
364 buf.put(src, offset, length);
369 public void write(byte[] src) throws IOException {
370 assertHasWritableBytes(src.length);
371 buf.position( (int) pointer );
373 pointer += src.length;
377 public void writeDouble(double value) throws IOException {
378 assertHasWritableBytes(8);
379 buf.position( (int) pointer );
380 buf.putDouble(value);
385 public void writeFloat(float value) throws IOException {
386 assertHasWritableBytes(4);
387 buf.position( (int) pointer );
393 public void writeInt(int value) throws IOException {
394 assertHasWritableBytes(4);
395 buf.position( (int) pointer );
401 public void writeLong(long value) throws IOException {
402 assertHasWritableBytes(8);
403 buf.position( (int) pointer );
409 public void writeShort(int value) throws IOException {
410 assertHasWritableBytes(2);
411 buf.position( (int) pointer );
412 buf.putShort( (short) value);
417 public void writeChar(int value) throws IOException {
418 assertHasWritableBytes(2);
419 buf.position( (int) pointer );
420 buf.putShort( (short) value);
425 public void writeBytes(String s) throws IOException {
426 int len = s.length();
427 assertHasWritableBytes(len);
428 buf.position( (int) pointer );
429 for (int i = 0 ; i < len ; i++) {
430 buf.put((byte)s.charAt(i));
436 public void writeChars(String s) throws IOException {
437 int len = s.length();
438 assertHasWritableBytes(len*2);
439 for (int i = 0 ; i < len ; i++) {
441 buf.put( (byte) ((v >>> 8) & 0xFF) );
442 buf.put( (byte) ((v >>> 0) & 0xFF) );
448 public void writeUTF(String s) throws IOException {
449 int len = UTF8.getModifiedUTF8EncodingByteLength(s);
451 UTF8.writeModifiedUTF(this, s);
454 void assertHasReadableBytes(long count) {
455 if (pointer + count > buf.limit())
456 throw new IndexOutOfBoundsException();
459 void assertHasWritableBytes(long count)
461 if (pointer + count > buf.limit())
462 setLength(pointer+count);
467 public void insertBytes(long bytes, ByteSide side) throws IOException {
468 if (pointer<0) throw new IndexOutOfBoundsException();
469 // 1. Increase length
470 long oldLength = length();
471 long newLength = Math.max(oldLength + bytes, pointer + bytes);
472 // No need to allocate
473 if (newLength<buf.capacity()) {
475 buf.limit((int)newLength);
477 // No need to move bytes
478 if (pointer>oldLength) return;
481 if (buf.hasArray()) {
482 System.arraycopy(buf.array(), (int) pointer, buf.array(), (int) (pointer+bytes), (int) (oldLength - pointer));
486 byte[] b = new byte[(int) (oldLength - pointer)];
487 buf.position((int)pointer);
489 buf.position( (int) (pointer + bytes) );
493 // Need to reallocate
495 long inc = Math.max(increment, newLength / 4);
496 ByteBuffer oldBuf = buf;
497 ByteBuffer newBuf = ByteBuffer.allocate((int) (newLength + inc));
498 newBuf.limit((int)newLength);
504 oldBuf.get(newBuf.array(), 0, (int)pointer);
507 if (pointer<oldLength)
508 oldBuf.get(newBuf.array(), (int)(pointer+bytes), (int)(oldLength-pointer));
516 public void removeBytes(long bytes, ByteSide side) throws IOException {
517 long oldLength = length();
518 long newLength = oldLength - bytes;
519 if (pointer<0 || pointer>=length()) throw new IndexOutOfBoundsException();
522 if (buf.hasArray()) {
523 System.arraycopy(buf.array(), (int)(pointer+bytes), buf.array(), (int) pointer, (int) (newLength-pointer) );
525 byte[] b = new byte[(int) (oldLength-pointer)];
526 buf.position((int) (pointer+bytes));
528 buf.position((int) (pointer));
532 buf.limit( (int) newLength );
536 public void setLength(long newLength) throws IOException {
537 int oldLength = (int) length();
538 if (oldLength==newLength) return;
539 if (newLength<=oldLength) {
540 buf.limit((int)newLength);
542 if (newLength<=buf.capacity()) {
543 buf.limit((int)newLength);
545 ByteBuffer oldBuf = buf;
546 long inc = Math.max(increment, newLength / 4);
547 ByteBuffer newBuf = ByteBuffer.allocate((int) (newLength + inc));
549 oldBuf.get(newBuf.array(), 0, oldLength);
550 newBuf.limit((int)newLength);
556 public long skipBytes(long bytes) throws IOException {
562 public int skipBytes(int bytes) throws IOException {
568 public String toString() {
569 return "Mem("+length()+")";