]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/util/binary/BinaryMemory.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / util / binary / BinaryMemory.java
1 /*******************************************************************************\r
2  * Copyright (c) 2010, 2016 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.databoard.util.binary;
13
14 import java.io.DataInputStream;\r
15 import java.io.IOException;\r
16 import java.io.InputStream;\r
17 import java.nio.ByteBuffer;\r
18
19 /**
20  * Rancom access memory blob
21  *
22  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
23  */
24 public class BinaryMemory implements RandomAccessBinary {
25
26         ByteBuffer buf;
27         long pointer;
28         /** the number of bytes added spare to the buffer when it is incremented */
29         int increment;
30         
31         /**
32          * New memory blob
33          */
34         public BinaryMemory() {
35                 buf = ByteBuffer.allocate(16);
36                 increment = 16;
37         }
38 \r
39         /**\r
40          * New memory blob\r
41          */\r
42         public BinaryMemory(byte[] data) {\r
43                 this.buf = ByteBuffer.wrap(data);\r
44         }\r
45         \r
46         /**\r
47          * New memory blob\r
48          */\r
49         public BinaryMemory(byte[] data, int offset, int length) {\r
50                 this.buf = ByteBuffer.wrap(data, offset, length);\r
51         }\r
52         
53         /**
54          * New memory blob
55          */
56         public BinaryMemory(int initialSize) {
57                 buf = ByteBuffer.allocate(initialSize);
58                 increment = Math.max(16, initialSize);
59         }
60         
61         /**
62          * New memory blob
63          */
64         public BinaryMemory(int initialSize, int increment) {
65                 buf = ByteBuffer.allocate(initialSize);
66                 this.increment = increment;
67         }
68         
69         /**
70          * Assume an existing byte buffer
71          * 
72          * @param buf buffer
73          */
74         public BinaryMemory(ByteBuffer buf) {
75                 this.buf = buf;
76         }
77         
78         /**
79          * Get the backend byte buffer. The result may change if BinaryMemory is 
80          * written.
81          * 
82          * @return byte buffer
83          */
84         public ByteBuffer toByteBuffer() {
85                 return buf;
86         }
87         
88         @Override
89         public void close() throws IOException {
90         }
91 \r
92         @Override\r
93         public boolean isOpen() {\r
94                 return true;\r
95         }\r
96         
97         @Override
98         public void flush() throws IOException {
99         }\r
100         \r
101         @Override\r
102         public void reset() throws IOException {\r
103         }
104
105         @Override
106         public byte readByte() {
107                 assertHasReadableBytes(1);              
108                 buf.position( (int) pointer );
109                 byte result = buf.get();
110                 pointer += 1;
111                 return result;
112         }\r
113         \r
114         int _read() {\r
115                 if (pointer >= buf.limit()) return -1;\r
116                 buf.position( (int) pointer );\r
117                 byte result = buf.get();\r
118                 pointer += 1;\r
119                 return result & 0xff;\r
120         }       \r
121         \r
122     public final String readLine() throws IOException {\r
123         StringBuffer input = new StringBuffer();\r
124         int c = -1;\r
125         boolean eol = false;\r
126 \r
127         while (!eol) {\r
128             switch (c = _read()) {\r
129             case -1:\r
130             case '\n':\r
131                 eol = true;\r
132                 break;\r
133             case '\r':\r
134                 eol = true;\r
135                 long cur = position();\r
136                 if ((_read()) != '\n') {\r
137                     position(cur);\r
138                 }\r
139                 break;\r
140             default:\r
141                 input.append((char)c);\r
142                 break;\r
143             }\r
144         }\r
145 \r
146         if ((c == -1) && (input.length() == 0)) {\r
147             return null;\r
148         }\r
149         return input.toString();\r
150     }   \r
151     \r
152     public final String readUTF() throws IOException {\r
153         return DataInputStream.readUTF(this);\r
154     }     \r
155         \r
156         @Override\r
157         public int readUnsignedByte() throws IOException {\r
158                 return readByte() & 0x000000ff;\r
159         }               
160 \r
161         @Override\r
162         public boolean readBoolean() throws IOException {\r
163                 assertHasReadableBytes(1);              \r
164                 buf.position( (int) pointer );\r
165                 byte result = buf.get();\r
166                 pointer += 1;\r
167                 return result!=0;\r
168         }\r
169         
170         @Override
171         public void readFully(byte[] dst, int offset, int length) {
172                 assertHasReadableBytes(length);
173                 buf.position( (int) pointer );
174                 buf.get(dst, offset, length);
175                 pointer += length;
176         }
177
178         @Override
179         public void readFully(byte[] dst) {
180                 assertHasReadableBytes(dst.length);             
181                 buf.position( (int) pointer );
182                 buf.get(dst);
183                 pointer += dst.length;
184         }
185
186         @Override
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());
194                 } else {
195                         buf.put(buf);
196                 }
197                 pointer += bytes;
198         }
199
200         @Override
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);
207                 } else {
208 //                      int len = Math.min( Math.min( buf.remaining(), this.buf.remaining() ), length);
209                         int len = length;
210                         int origLimit = this.buf.limit();
211                         try {
212                                 this.buf.limit(this.buf.position()+len);
213                                 buf.put(this.buf);
214                         } finally {
215                                 this.buf.limit(origLimit);
216                         }
217                 }
218                 pointer += length;
219         }
220
221         @Override
222         public double readDouble() {
223                 assertHasReadableBytes(8);
224                 buf.position( (int) pointer );
225                 double value = buf.getDouble();
226                 pointer += 8;
227                 return value;
228         }
229
230         @Override
231         public float readFloat() {
232                 assertHasReadableBytes(4);
233                 buf.position( (int) pointer );
234                 float result = buf.getFloat();
235                 pointer += 4;
236                 return result;
237         }
238
239         @Override
240         public int readInt() {
241                 assertHasReadableBytes(4);
242                 buf.position( (int) pointer );
243                 int value = buf.getInt();
244                 pointer += 4;
245                 return value;
246         }
247
248         @Override
249         public long readLong() {
250                 assertHasReadableBytes(8);
251                 buf.position( (int) pointer );
252                 long value = buf.getLong();
253                 pointer += 8;
254                 return value;
255         }
256
257         @Override
258         public short readShort() {
259                 assertHasReadableBytes(2);
260                 buf.position( (int) pointer );
261                 short result = buf.getShort();
262                 pointer += 2;
263                 return result;
264         }\r
265         \r
266         @Override\r
267         public char readChar() {\r
268                 assertHasReadableBytes(2);\r
269                 buf.position( (int) pointer );\r
270                 char result = buf.getChar();\r
271                 pointer += 2;\r
272                 return result;\r
273         }       \r
274         \r
275         @Override\r
276         public int readUnsignedShort() {\r
277                 assertHasReadableBytes(2);\r
278                 buf.position( (int) pointer );\r
279                 int result = buf.getShort() & 0xffff;\r
280                 pointer += 2;\r
281                 return result;\r
282         }       
283
284         @Override
285         public long length() {
286                 return buf.limit();
287         }
288         
289         @Override
290         public long position() {
291                 return pointer;
292         }
293         
294         @Override
295         public void position(long newPosition) throws IOException {
296                 this.pointer = newPosition;
297         }
298         
299         @Override
300         public void write(int b) throws IOException {
301                 assertHasWritableBytes(1);
302                 buf.position( (int) pointer );
303                 buf.put((byte) b);
304                 pointer += 1;
305         }\r
306         \r
307         @Override\r
308         public void writeByte(int b) throws IOException {\r
309                 assertHasWritableBytes(1);\r
310                 buf.position( (int) pointer );\r
311                 buf.put((byte) b);\r
312                 pointer += 1;\r
313         }       \r
314         \r
315         @Override\r
316         public void writeBoolean(boolean v) throws IOException {\r
317                 assertHasWritableBytes(1);\r
318                 buf.position( (int) pointer );\r
319                 buf.put( (byte) (v ? 1 : 0) );\r
320                 pointer += 1;\r
321         }
322
323         @Override
324         public void writeFully(ByteBuffer src) throws IOException {
325                 long bytes = src.remaining();
326                 assertHasWritableBytes( bytes );
327                 buf.position( (int) pointer );
328                 buf.put(src);
329                 pointer += bytes;
330         }
331
332         @Override
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);
339                 } else {
340                         for (int i=0; i<length; i++)
341                                 buf.put(src.get());
342                 }
343                 pointer += length;
344         }
345
346         
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);                     
354                         pointer += n;
355                 }
356                 long newLen = length();
357                 if (newLen>oldLen & pointer<newLen) setLength(pointer);
358         }
359
360         @Override
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);
365                 pointer += length;
366         }
367
368         @Override
369         public void write(byte[] src) throws IOException {
370                 assertHasWritableBytes(src.length);
371                 buf.position( (int) pointer );
372                 buf.put(src);
373                 pointer += src.length;
374         }
375
376         @Override
377         public void writeDouble(double value) throws IOException {
378                 assertHasWritableBytes(8);
379                 buf.position( (int) pointer );
380                 buf.putDouble(value);
381                 pointer += 8;
382         }
383
384         @Override
385         public void writeFloat(float value) throws IOException {
386                 assertHasWritableBytes(4);
387                 buf.position( (int) pointer );
388                 buf.putFloat(value);
389                 pointer += 4;
390         }
391
392         @Override
393         public void writeInt(int value) throws IOException {
394                 assertHasWritableBytes(4);
395                 buf.position( (int) pointer );
396                 buf.putInt(value);
397                 pointer += 4;
398         }
399
400         @Override
401         public void writeLong(long value) throws IOException {
402                 assertHasWritableBytes(8);
403                 buf.position( (int) pointer );
404                 buf.putLong(value);
405                 pointer += 8;
406         }
407
408         @Override
409         public void writeShort(int value) throws IOException {
410                 assertHasWritableBytes(2);
411                 buf.position( (int) pointer );
412                 buf.putShort( (short) value);
413                 pointer += 2;
414         }\r
415         \r
416         @Override\r
417         public void writeChar(int value) throws IOException {\r
418                 assertHasWritableBytes(2);\r
419                 buf.position( (int) pointer );\r
420                 buf.putShort( (short) value);\r
421                 pointer += 2;\r
422         }       \r
423         \r
424         @Override\r
425         public void writeBytes(String s) throws IOException {\r
426                 int len = s.length();\r
427                 assertHasWritableBytes(len);\r
428                 buf.position( (int) pointer );\r
429                 for (int i = 0 ; i < len ; i++) {\r
430                     buf.put((byte)s.charAt(i));\r
431                 }\r
432                 pointer += len;\r
433         }       \r
434         \r
435         @Override\r
436         public void writeChars(String s) throws IOException {\r
437         int len = s.length();\r
438                 assertHasWritableBytes(len*2);\r
439         for (int i = 0 ; i < len ; i++) {\r
440             int v = s.charAt(i);\r
441             buf.put( (byte) ((v >>> 8) & 0xFF) ); \r
442             buf.put( (byte) ((v >>> 0) & 0xFF) ); \r
443         }\r
444                 pointer += len*2;\r
445         }\r
446         \r
447         @Override\r
448         public void writeUTF(String s) throws IOException {\r
449                 int len = UTF8.getModifiedUTF8EncodingByteLength(s);\r
450                 writeShort(len);\r
451                 UTF8.writeModifiedUTF(this, s);\r
452         }       
453
454         void assertHasReadableBytes(long count) {
455                 if (pointer + count > buf.limit())
456                         throw new IndexOutOfBoundsException();
457         }
458         
459         void assertHasWritableBytes(long count) 
460         throws IOException {
461                 if (pointer + count > buf.limit()) 
462                         setLength(pointer+count);
463         }
464
465
466         @Override
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()) {
474                         // Update limit
475                         buf.limit((int)newLength);
476                         
477                         // No need to move bytes
478                         if (pointer>oldLength) return;
479                                 
480                         // Move bytes
481                         if (buf.hasArray()) {
482                                 System.arraycopy(buf.array(), (int) pointer, buf.array(), (int) (pointer+bytes), (int) (oldLength - pointer));
483                         } 
484                         else 
485                         {
486                                 byte[] b = new byte[(int) (oldLength - pointer)];
487                                 buf.position((int)pointer);
488                                 buf.get(b);
489                                 buf.position( (int) (pointer + bytes) );
490                                 buf.put(b);
491                         }
492                 } else
493                 // Need to reallocate
494                 {
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);
499                         
500                         newBuf.position(0);
501                         oldBuf.position(0);
502
503                         // Copy left side
504                         oldBuf.get(newBuf.array(), 0, (int)pointer);
505                         
506                         // Copy right side
507                         if (pointer<oldLength) 
508                         oldBuf.get(newBuf.array(), (int)(pointer+bytes), (int)(oldLength-pointer));
509                         
510                         buf = newBuf;
511                 }
512                 
513         }
514         
515         @Override
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();
520                 
521                 // move some bytes
522                 if (buf.hasArray()) {
523                         System.arraycopy(buf.array(), (int)(pointer+bytes), buf.array(), (int) pointer, (int) (newLength-pointer) ); 
524                 } else {
525                         byte[] b = new byte[(int) (oldLength-pointer)];
526                         buf.position((int) (pointer+bytes));
527                         buf.get(b);
528                         buf.position((int) (pointer));
529                         buf.put(b);
530                 }
531                 
532                 buf.limit( (int) newLength );
533         }
534
535         @Override
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);
541                 } else
542                 if (newLength<=buf.capacity()) {
543                         buf.limit((int)newLength);
544                 } else {
545                         ByteBuffer oldBuf = buf;
546                         long inc = Math.max(increment, newLength / 4);
547                         ByteBuffer newBuf = ByteBuffer.allocate((int) (newLength + inc));
548                         oldBuf.position(0);
549                         oldBuf.get(newBuf.array(), 0, oldLength);
550                         newBuf.limit((int)newLength);
551                         buf = newBuf;
552                 }               
553         }
554
555         @Override
556         public long skipBytes(long bytes) throws IOException {
557                 pointer += bytes;\r
558                 return bytes;
559         }
560 \r
561         @Override\r
562         public int skipBytes(int bytes) throws IOException {\r
563                 pointer += bytes;\r
564                 return bytes;\r
565         }\r
566         
567         @Override
568         public String toString() {
569                 return "Mem("+length()+")";
570         }
571         
572 }
573