1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.mina.codec;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.nio.BufferOverflowException;
24 import java.nio.BufferUnderflowException;
25 import java.nio.ByteBuffer;
26 import java.nio.ByteOrder;
27 import java.nio.InvalidMarkException;
28 import java.nio.ReadOnlyBufferException;
29
30
31
32
33
34
35
36
37
38
39
40
41 public final class IoBuffer {
42 private static final int BYTE_MASK = 0xff;
43
44 private static final long BYTE_MASK_L = 0xffL;
45
46
47
48
49 public static IoBuffer allocate(int capacity) {
50 return wrap(ByteBuffer.allocate(capacity));
51 }
52
53
54
55
56 public static IoBuffer allocateDirect(int capacity) {
57 return wrap(ByteBuffer.allocateDirect(capacity));
58 }
59
60
61
62
63
64
65 public static IoBuffer newInstance() {
66 return new IoBuffer();
67 }
68
69
70
71
72 public static IoBuffer wrap(byte[]... arrays) {
73 IoBuffer ioBuffer = new IoBuffer();
74 for (byte[] array : arrays) {
75 ioBuffer.add(ByteBuffer.wrap(array));
76 }
77 return ioBuffer;
78 }
79
80
81
82
83 public static IoBuffer wrap(byte[] array, int offset, int length) {
84 return wrap(ByteBuffer.wrap(array, offset, length));
85 }
86
87
88
89
90
91
92
93 public static IoBuffer wrap(ByteBuffer... buffers) {
94 IoBuffer ioBuffer = new IoBuffer();
95 for (ByteBuffer b : buffers) {
96 ioBuffer.add(b);
97 }
98 return ioBuffer;
99 }
100
101 private ByteOrder bo = ByteOrder.BIG_ENDIAN;
102
103 private int capacity = 0;
104
105 private boolean direct = true;
106
107 private BufferNode head, tail;
108
109
110 private Pointer limit = new Pointer();
111
112
113 private Pointer mark = new Pointer();
114
115
116 private Pointer position = new Pointer();
117
118
119 private boolean readonly = false;
120
121 private IoBuffer() {
122 limit(0);
123 position(0);
124 mark = null;
125 }
126
127
128
129
130
131
132
133 public IoBuffer add(ByteBuffer... buffers) {
134 for (ByteBuffer buffer : buffers) {
135 enqueue(buffer.slice());
136 }
137 return this;
138 }
139
140
141
142
143 public byte[] array() {
144 if (capacity == 0) {
145 return new byte[0];
146 }
147 if (head.hasNext()) {
148 throw new UnsupportedOperationException();
149 }
150 return head.getBuffer().array();
151 }
152
153
154
155
156 public int arrayOffset() {
157 if (capacity == 0) {
158 return 0;
159 }
160 if (head.hasNext()) {
161 throw new UnsupportedOperationException();
162 }
163 return head.getBuffer().arrayOffset();
164 }
165
166
167
168
169
170
171
172
173
174
175 public InputStream asInputStream() {
176 return new InputStream() {
177
178 @Override
179 public int read() throws IOException {
180 return hasRemaining() ? get() & BYTE_MASK : -1;
181 }
182
183 @Override
184 public int read(byte[] b, int off, int len) throws IOException {
185 if (!hasRemaining()) {
186 return -1;
187 }
188
189 int toRead = Math.min(remaining(), len);
190 get(b, off, toRead);
191 return toRead;
192 }
193 };
194 }
195
196
197
198
199 public IoBuffer asReadOnlyBuffer() {
200 IoBuffer buffer = duplicate();
201 buffer.readonly = true;
202 return buffer;
203 }
204
205
206
207
208 public int capacity() {
209 return capacity;
210 }
211
212
213
214
215 public IoBuffer clear() {
216 position = getPointerByPosition(0);
217 limit = getPointerByPosition(capacity);
218 mark = null;
219 return this;
220 }
221
222
223
224
225 public IoBuffer compact() {
226 for (int i = 0; i < remaining(); i++) {
227 put(i, get(i + position.getPosition()));
228 }
229 position(limit() - position());
230 limit(capacity);
231 mark = null;
232 return this;
233 }
234
235
236
237
238
239
240 public IoBuffer duplicate() {
241 IoBuffer buffer = new IoBuffer();
242
243 for (BufferNode node = head; node != null; node = node.getNext()) {
244 ByteBuffer byteBuffer = node.getBuffer().duplicate();
245 byteBuffer.rewind();
246 buffer.enqueue(byteBuffer);
247 }
248 buffer.position(position());
249 buffer.limit(limit());
250 buffer.mark = mark != null ? getPointerByPosition(mark.getPosition()) : null;
251
252 buffer.readonly = readonly;
253 return buffer;
254 }
255
256 private void enqueue(ByteBuffer buffer) {
257
258 if (buffer.isReadOnly()) {
259 readonly = true;
260 }
261
262 if (!buffer.isDirect()) {
263 direct = false;
264 }
265 if (buffer.remaining() > 0) {
266 BufferNode newnode = new BufferNode(buffer, capacity);
267 capacity += buffer.capacity();
268
269 if (head == null) {
270 head = newnode;
271 position = getPointerByPosition(0);
272 } else {
273 tail.setNext(newnode);
274 }
275 tail = newnode;
276
277 limit = getPointerByPosition(capacity);
278 }
279 }
280
281
282
283
284 @Override
285 public boolean equals(Object ob) {
286 if (this == ob) {
287 return true;
288 }
289 if (!(ob instanceof IoBuffer)) {
290 return false;
291 }
292 IoBuffer that = (IoBuffer) ob;
293 if (this.remaining() != that.remaining()) {
294 return false;
295 }
296 int p = this.position();
297 int q = that.position();
298 while (this.hasRemaining() && that.hasRemaining()) {
299 if (this.get() != that.get()) {
300 this.position(p);
301 that.position(q);
302 return false;
303 }
304
305 }
306 this.position(p);
307 that.position(q);
308 return true;
309 }
310
311
312
313
314
315
316
317 public IoBuffer extend(int size) {
318 ByteBuffer extension = isDirect() ? ByteBuffer.allocateDirect(size) : ByteBuffer.allocate(size);
319 add(extension);
320 return this;
321 }
322
323
324
325
326 public IoBuffer flip() {
327 limit = position;
328 position = getPointerByPosition(0);
329 return this;
330 }
331
332
333
334
335 public byte get() {
336 if (!hasRemaining()) {
337 throw new BufferUnderflowException();
338 }
339
340 return get(position);
341 }
342
343
344
345
346 public IoBuffer get(byte[] dst) {
347 get(dst, 0, dst.length);
348 return this;
349 }
350
351
352
353
354 public IoBuffer get(byte[] dst, int offset, int length) {
355 if (remaining() < length) {
356 throw new BufferUnderflowException();
357 }
358 int remainsToCopy = length;
359 int currentOffset = offset;
360
361 while (remainsToCopy > 0) {
362 position.updatePos();
363 position.getNode().getBuffer().position(position.getPositionInNode());
364 ByteBuffer currentBuffer = position.getNode().getBuffer();
365 int blocksize = Math.min(remainsToCopy, currentBuffer.remaining());
366 position.getNode().getBuffer().get(dst, currentOffset, blocksize);
367
368 currentOffset += blocksize;
369 remainsToCopy -= blocksize;
370
371 position.incrementPosition(blocksize);
372
373 position.getNode().getBuffer().position(0);
374 }
375 return this;
376 }
377
378
379
380
381 public byte get(int index) {
382 if (index >= limit.getPosition()) {
383 throw new IndexOutOfBoundsException();
384 }
385 return get(getPointerByPosition(index));
386 }
387
388 private byte get(Pointer pos) {
389 pos.updatePos();
390 byte b = pos.getNode().getBuffer().get(pos.getPositionInNode());
391 pos.incrPosition();
392 return b;
393 }
394
395
396
397
398 public char getChar() {
399 return getChar(position);
400 }
401
402
403
404
405 public char getChar(int index) {
406 return getChar(getPointerByPosition(index));
407 }
408
409 private char getChar(Pointer position) {
410 return (char) getShort(position);
411 }
412
413
414
415
416 public double getDouble() {
417 return Double.longBitsToDouble(getLong());
418 }
419
420
421
422
423 public double getDouble(int index) {
424 return getDouble(getPointerByPosition(index));
425 }
426
427 private double getDouble(Pointer pos) {
428 return Double.longBitsToDouble(getLong(pos));
429 }
430
431
432
433
434 public float getFloat() {
435 return getFloat(position);
436 }
437
438
439
440
441 public float getFloat(int index) {
442 return getFloat(getPointerByPosition(index));
443 }
444
445 private float getFloat(Pointer pos) {
446 return Float.intBitsToFloat(getInt(pos));
447 }
448
449
450
451
452 public int getInt() {
453 return getInt(position);
454 }
455
456
457
458
459 public int getInt(int index) {
460 return getInt(getPointerByPosition(index));
461 }
462
463 private int getInt(Pointer pos) {
464 if (pos.getPosition() > capacity - Integer.SIZE / Byte.SIZE) {
465 throw new BufferUnderflowException();
466 }
467
468 int out = 0;
469 for (int i = 0; i < Integer.SIZE; i += Byte.SIZE) {
470 out |= (get(pos) & BYTE_MASK) << (bo == ByteOrder.BIG_ENDIAN ? (Integer.SIZE - Byte.SIZE) - i : i);
471 }
472 return out;
473 }
474
475
476
477
478 public long getLong() {
479 return getLong(position);
480 }
481
482
483
484
485 public long getLong(int index) {
486 return getLong(getPointerByPosition(index));
487 }
488
489 private long getLong(Pointer pos) {
490 if (pos.getPosition() > capacity - Long.SIZE / Byte.SIZE) {
491 throw new BufferUnderflowException();
492 }
493
494 long out = 0;
495 for (int i = 0; i < Long.SIZE; i += Byte.SIZE) {
496 out |= (get(pos) & BYTE_MASK_L) << (bo == ByteOrder.BIG_ENDIAN ? (Long.SIZE - Byte.SIZE) - i : i);
497 }
498 return out;
499 }
500
501 private Pointer getPointerByPosition(int pos) {
502 return new Pointer(pos);
503 }
504
505
506
507
508 public short getShort() {
509 return getShort(position);
510 }
511
512
513
514
515 public long getShort(int index) {
516 return getShort(getPointerByPosition(index));
517 }
518
519 private short getShort(Pointer pos) {
520 if (pos.getPosition() > capacity - Short.SIZE / Byte.SIZE) {
521 throw new BufferUnderflowException();
522 }
523 if (bo == ByteOrder.BIG_ENDIAN) {
524 return (short) ((get(pos) & BYTE_MASK) << Byte.SIZE | (get(pos) & BYTE_MASK));
525 } else {
526 return (short) ((get(pos) & BYTE_MASK) | (get(pos) & BYTE_MASK) << Byte.SIZE);
527 }
528 }
529
530
531
532
533 @Override
534 public int hashCode() {
535 int hash = 0;
536 Pointer oldPos = position.duplicate();
537 while (hasRemaining()) {
538 hash *= 31;
539 hash += get();
540 }
541 position = oldPos;
542 return hash;
543 }
544
545
546
547
548 public boolean hasRemaining() {
549 return remaining() > 0;
550 }
551
552
553
554
555 public boolean isDirect() {
556 return direct;
557 }
558
559
560
561
562 public boolean isReadOnly() {
563 return readonly;
564 }
565
566
567
568
569 public int limit() {
570 return limit.getPosition();
571 }
572
573
574
575
576 public void limit(int newLimit) {
577 this.limit = getPointerByPosition(newLimit);
578 }
579
580
581
582
583 public void mark() {
584 this.mark = position.duplicate();
585 }
586
587
588
589
590
591
592
593
594
595
596
597 public ByteOrder order() {
598 return bo;
599 }
600
601
602
603
604
605
606
607
608
609 public IoBuffer order(ByteOrder bo) {
610 this.bo = bo != null ? bo : ByteOrder.LITTLE_ENDIAN;
611
612 return this;
613 }
614
615
616
617
618 public int position() {
619 return position.getPosition();
620 }
621
622
623
624
625 public void position(int newPosition) {
626 if (newPosition > limit() || newPosition < 0) {
627 throw new IllegalArgumentException();
628 }
629
630 if (mark != null && mark.getPosition() > newPosition) {
631 mark = null;
632 }
633
634 this.position.setPosition(newPosition);
635 }
636
637
638
639
640 public IoBuffer put(byte b) {
641 if (readonly) {
642 throw new ReadOnlyBufferException();
643 }
644 if (position.getPosition() >= limit.getPosition()) {
645 throw new BufferUnderflowException();
646 }
647
648 put(position, b);
649 return this;
650 }
651
652
653
654
655 public IoBuffer put(byte[] src) {
656 put(src, 0, src.length);
657 return this;
658 }
659
660
661
662
663 public IoBuffer put(ByteBuffer src) {
664
665 if (remaining() < src.remaining()) {
666 throw new BufferOverflowException();
667 }
668 if (isReadOnly()) {
669 throw new ReadOnlyBufferException();
670 }
671
672 while (src.hasRemaining()) {
673 put(src.get());
674 }
675
676 return this;
677 }
678
679
680
681
682 public IoBuffer put(IoBuffer src) {
683 if (src == this) {
684 throw new IllegalArgumentException();
685 }
686
687 if (remaining() < src.remaining()) {
688 throw new BufferOverflowException();
689 }
690 if (isReadOnly()) {
691 throw new ReadOnlyBufferException();
692 }
693
694 while (src.hasRemaining()) {
695 put(src.get());
696 }
697
698 return this;
699 }
700
701
702
703
704 public IoBuffer put(byte[] src, int offset, int length) {
705 if (readonly) {
706 throw new ReadOnlyBufferException();
707 }
708 if (remaining() < length) {
709 throw new BufferUnderflowException();
710 }
711
712 int remainsToCopy = length;
713 int currentOffset = offset;
714 position.getNode().getBuffer().position(position.getPositionInNode());
715 while (remainsToCopy > 0) {
716 position.updatePos();
717
718 ByteBuffer currentBuffer = position.getNode().getBuffer();
719 int blocksize = Math.min(remainsToCopy, currentBuffer.remaining());
720 position.getNode().getBuffer().put(src, currentOffset, blocksize);
721
722 currentOffset += blocksize;
723 remainsToCopy -= blocksize;
724
725 position.incrementPosition(blocksize);
726 }
727 position.getNode().getBuffer().position(0);
728 return this;
729 }
730
731
732
733
734 public IoBuffer put(int index, byte value) {
735 if (index >= limit.getPosition()) {
736 throw new IndexOutOfBoundsException();
737 }
738 Pointer p = getPointerByPosition(index);
739 put(p, value);
740 return this;
741 }
742
743 private IoBuffer put(Pointer pos, byte b) {
744 pos.updatePos();
745 pos.getNode().getBuffer().put(pos.getPositionInNode(), b);
746 pos.incrPosition();
747 return this;
748 }
749
750
751
752
753 public IoBuffer putChar(char value) {
754 return putChar(position, value);
755 }
756
757
758
759
760 public IoBuffer putChar(int index, char value) {
761 return putChar(getPointerByPosition(index), value);
762 }
763
764 private IoBuffer putChar(Pointer index, char value) {
765 return putShort(index, (short) value);
766 }
767
768
769
770
771 public IoBuffer putDouble(double value) {
772 return putDouble(position, value);
773 }
774
775
776
777
778 public IoBuffer putDouble(int index, double value) {
779 return putDouble(getPointerByPosition(index), value);
780 }
781
782 private IoBuffer putDouble(Pointer pos, double value) {
783 return putLong(pos, Double.doubleToLongBits(value));
784 }
785
786
787
788
789 public IoBuffer putFloat(float value) {
790 return putFloat(position, value);
791 }
792
793
794
795
796 public IoBuffer putFloat(int index, float value) {
797 return putFloat(getPointerByPosition(index), value);
798 }
799
800 private IoBuffer putFloat(Pointer pointer, float value) {
801 return putInt(pointer, Float.floatToIntBits(value));
802 }
803
804
805
806
807 public IoBuffer putInt(int value) {
808 return putInt(position, value);
809 }
810
811
812
813
814 public IoBuffer putInt(int index, int value) {
815 return putInt(getPointerByPosition(index), value);
816 }
817
818 private IoBuffer putInt(Pointer pointer, int value) {
819 if (position.getPosition() > pointer.getPosition()
820 || pointer.getPosition() > limit.getPosition() - Integer.SIZE / Byte.SIZE) {
821 throw new BufferUnderflowException();
822 }
823 for (int i = 0; i < Integer.SIZE; i += Byte.SIZE) {
824 put(pointer, (byte) (value >> (bo == ByteOrder.BIG_ENDIAN ? (Integer.SIZE - Byte.SIZE) - i : i)));
825 }
826 return this;
827 }
828
829
830
831
832 public IoBuffer putLong(int index, long value) {
833 return putLong(getPointerByPosition(index), value);
834 }
835
836
837
838
839 public IoBuffer putLong(long value) {
840 return putLong(position, value);
841 }
842
843 private IoBuffer putLong(Pointer pointer, long value) {
844 if (position.getPosition() > pointer.getPosition()
845 || pointer.getPosition() > limit.getPosition() - Long.SIZE / Byte.SIZE) {
846 throw new BufferUnderflowException();
847 }
848 for (int i = 0; i < Long.SIZE; i += Byte.SIZE) {
849 put(pointer, (byte) (value >> (bo == ByteOrder.BIG_ENDIAN ? (Long.SIZE - Byte.SIZE) - i : i)));
850 }
851
852 return this;
853 }
854
855
856
857
858 public IoBuffer putShort(int index, short value) {
859 return putShort(getPointerByPosition(index), value);
860 }
861
862 private IoBuffer putShort(Pointer pointer, short value) {
863 if (position.getPosition() > pointer.getPosition()
864 || pointer.getPosition() > limit.getPosition() - Short.SIZE / Byte.SIZE) {
865 throw new BufferUnderflowException();
866 }
867 for (int i = 0; i < Short.SIZE; i += Byte.SIZE) {
868 put(pointer, (byte) (value >> (bo == ByteOrder.BIG_ENDIAN ? Byte.SIZE - i : i)));
869 }
870 return this;
871 }
872
873
874
875
876 public IoBuffer putShort(short value) {
877 return putShort(position, value);
878 }
879
880
881
882
883 public int remaining() {
884 return limit() - position();
885 }
886
887
888
889
890 public IoBuffer reset() {
891 if (mark == null) {
892 throw new InvalidMarkException();
893 }
894 position = mark.duplicate();
895 return this;
896 }
897
898
899
900
901 public IoBuffer rewind() {
902 position(0);
903 mark = getPointerByPosition(-1);
904 return this;
905 }
906
907
908
909
910 public IoBuffer slice() {
911 position.updatePos();
912 IoBuffer out = new IoBuffer();
913 out.order(order());
914
915 position.getNode().getBuffer().position(position.getPositionInNode());
916 if (hasRemaining()) {
917 tail.getBuffer().limit(limit.getPositionInNode());
918 for (BufferNode node = position.getNode(); node != limit.getNode(); node = node.getNext()) {
919 if (node != head) {
920 node.getBuffer().position(0);
921 }
922 out.add(node.getBuffer());
923 }
924 if (tail != head) {
925 tail.getBuffer().position(0);
926 }
927 out.add(tail.getBuffer().slice());
928 tail.getBuffer().limit(tail.getBuffer().capacity());
929 }
930 position.getNode().getBuffer().position(0);
931
932 return out;
933 }
934
935 @Override
936 public String toString() {
937 StringBuilder sb = new StringBuilder();
938 sb.append(getClass().getName());
939 sb.append("[pos=");
940 sb.append(position());
941 sb.append(" lim=");
942 sb.append(limit());
943 sb.append(" cap=");
944 sb.append(capacity());
945 sb.append("]");
946 return sb.toString();
947 }
948
949 private static final class BufferNode {
950 private final ByteBuffer buffer;
951
952 private BufferNode next;
953
954 private final int offset;
955
956 public BufferNode(ByteBuffer buffer, int offset) {
957 this.buffer = buffer;
958 this.offset = offset;
959 }
960
961 public ByteBuffer getBuffer() {
962 return buffer;
963 }
964
965 public BufferNode getNext() {
966 return next;
967 }
968
969 public boolean hasNext() {
970 return next != null;
971 }
972
973 public void setNext(BufferNode next) {
974 this.next = next;
975 }
976
977 @Override
978 public String toString() {
979 return "BufferNode [offset=" + offset + ", buffer=" + buffer + "]";
980 }
981 }
982
983 private final class Pointer {
984
985 private BufferNode node;
986
987 private int positionInBuffer;
988
989 public Pointer(int position) {
990 this();
991
992 setPosition(position);
993 }
994
995 public Pointer() {
996 }
997
998 public Pointer duplicate() {
999 return new Pointer(getPosition());
1000 }
1001
1002 public BufferNode getNode() {
1003 return node;
1004 }
1005
1006 public int getPosition() {
1007 return positionInBuffer + (node == null ? 0 : node.offset);
1008 }
1009
1010 public int getPositionInNode() {
1011 updatePos();
1012 return positionInBuffer;
1013 }
1014
1015 public void incrPosition() {
1016 incrementPosition(1);
1017 }
1018
1019 public void setPosition(int newPosition) {
1020 if (node == null || newPosition < node.offset) {
1021 node = head;
1022 }
1023 positionInBuffer = node == null ? 0 : newPosition - node.offset;
1024 }
1025
1026 public void incrementPosition(int positionIncrement) {
1027 positionInBuffer += positionIncrement;
1028 }
1029
1030 @Override
1031 public String toString() {
1032 StringBuilder sb = new StringBuilder();
1033 sb.append(getClass().getName());
1034 sb.append("[pos=");
1035 sb.append(getPosition());
1036 sb.append(", node=");
1037 sb.append(getNode());
1038 sb.append("]");
1039 return sb.toString();
1040 }
1041
1042 public void updatePos() {
1043 while (node != null && positionInBuffer >= node.getBuffer().capacity() && node.hasNext()) {
1044 positionInBuffer -= node.getBuffer().capacity();
1045 node = node.getNext();
1046 }
1047 }
1048 }
1049 }