1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.util.byteaccess;
21
22 import java.nio.ByteOrder;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Collections;
26
27 import org.apache.mina.core.buffer.IoBuffer;
28 import org.apache.mina.util.byteaccess.ByteArrayList.Node;
29
30
31
32
33
34
35
36
37
38
39 public final class CompositeByteArray extends AbstractByteArray {
40
41
42
43
44
45
46 public interface CursorListener {
47
48
49
50
51
52
53 void enteredFirstComponent(int componentIndex, ByteArray component);
54
55
56
57
58
59
60
61 void enteredNextComponent(int componentIndex, ByteArray component);
62
63
64
65
66
67
68
69 void enteredPreviousComponent(int componentIndex, ByteArray component);
70
71
72
73
74
75
76
77 void enteredLastComponent(int componentIndex, ByteArray component);
78 }
79
80
81
82
83 private final ByteArrayListss/ByteArrayList.html#ByteArrayList">ByteArrayList bas = new ByteArrayList();
84
85
86
87
88 private ByteOrder order;
89
90
91
92
93 private final ByteArrayFactory byteArrayFactory;
94
95
96
97
98 public CompositeByteArray() {
99 this(null);
100 }
101
102
103
104
105
106
107
108
109 public CompositeByteArray(ByteArrayFactory byteArrayFactory) {
110 this.byteArrayFactory = byteArrayFactory;
111 }
112
113
114
115
116 public ByteArray getFirst() {
117 if (bas.isEmpty()) {
118 return null;
119 }
120
121 return bas.getFirst().getByteArray();
122 }
123
124
125
126
127
128
129
130 public void addFirst(ByteArray ba) {
131 addHook(ba);
132 bas.addFirst(ba);
133 }
134
135
136
137
138
139
140 public ByteArray removeFirst() {
141 Node node = bas.removeFirst();
142 return node == null ? null : node.getByteArray();
143 }
144
145
146
147
148
149
150
151
152
153
154
155 public ByteArray removeTo(int index) {
156 if (index < first() || index > last()) {
157 throw new IndexOutOfBoundsException();
158 }
159
160
161 CompositeByteArraysiteByteArray.html#CompositeByteArray">CompositeByteArray prefix = new CompositeByteArray(byteArrayFactory);
162 int remaining = index - first();
163
164 while (remaining > 0) {
165 ByteArray component = removeFirst();
166
167 if (component.last() <= remaining) {
168
169 prefix.addLast(component);
170 remaining -= component.last();
171 } else {
172
173
174
175
176 IoBuffer bb = component.getSingleIoBuffer();
177
178
179 int originalLimit = bb.limit();
180
181
182 bb.position(0);
183
184
185 bb.limit(remaining);
186
187
188 IoBuffer bb1 = bb.slice();
189
190
191 bb.position(remaining);
192
193
194 bb.limit(originalLimit);
195
196
197 IoBuffer bb2 = bb.slice();
198
199
200 ByteArray ba1 = new BufferByteArray(bb1) {
201 @Override
202 public void free() {
203
204 }
205 };
206
207
208 prefix.addLast(ba1);
209 remaining -= ba1.last();
210
211
212 final ByteArray componentFinal = component;
213 ByteArray ba2 = new BufferByteArray(bb2) {
214 @Override
215 public void free() {
216 componentFinal.free();
217 }
218 };
219
220
221 addFirst(ba2);
222 }
223 }
224
225
226 return prefix;
227 }
228
229
230
231
232
233
234 public void addLast(ByteArray ba) {
235 addHook(ba);
236 bas.addLast(ba);
237 }
238
239
240
241
242
243
244 public ByteArray removeLast() {
245 Node node = bas.removeLast();
246
247 return node == null ? null : node.getByteArray();
248 }
249
250
251
252
253 @Override
254 public void free() {
255 while (!bas.isEmpty()) {
256 Node node = bas.getLast();
257 node.getByteArray().free();
258 bas.removeLast();
259 }
260 }
261
262
263
264
265 @Override
266 public Iterable<IoBuffer> getIoBuffers() {
267 if (bas.isEmpty()) {
268 return Collections.emptyList();
269 }
270
271 Collection<IoBuffer> result = new ArrayList<>();
272 Node node = bas.getFirst();
273
274 for (IoBuffer bb : node.getByteArray().getIoBuffers()) {
275 result.add(bb);
276 }
277
278 while (node.hasNextNode()) {
279 node = node.getNextNode();
280
281 for (IoBuffer bb : node.getByteArray().getIoBuffers()) {
282 result.add(bb);
283 }
284 }
285
286 return result;
287 }
288
289
290
291
292 @Override
293 public IoBuffer getSingleIoBuffer() {
294 if (byteArrayFactory == null) {
295 throw new IllegalStateException(
296 "Can't get single buffer from CompositeByteArray unless it has a ByteArrayFactory.");
297 }
298
299 if (bas.isEmpty()) {
300 ByteArray ba = byteArrayFactory.create(1);
301 return ba.getSingleIoBuffer();
302 }
303
304 int actualLength = last() - first();
305
306 Node firstNode = bas.getFirst();
307 ByteArray ba = firstNode.getByteArray();
308
309 if (ba.last() == actualLength) {
310 return ba.getSingleIoBuffer();
311 }
312
313
314 ByteArray target = byteArrayFactory.create(actualLength);
315 IoBuffer bb = target.getSingleIoBuffer();
316 Cursor cursor = cursor();
317 cursor.put(bb);
318
319 while (!bas.isEmpty()) {
320 Node node = bas.getLast();
321 ByteArray component = node.getByteArray();
322 bas.removeLast();
323 component.free();
324 }
325
326 bas.addLast(target);
327
328 return bb;
329 }
330
331
332
333
334 @Override
335 public Cursor cursor() {
336 return new CursorImpl();
337 }
338
339
340
341
342 @Override
343 public Cursor cursor(int index) {
344 return new CursorImpl(index);
345 }
346
347
348
349
350
351
352
353
354 public Cursor cursor(CursorListener listener) {
355 return new CursorImpl(listener);
356 }
357
358
359
360
361
362
363
364
365 public Cursor cursor(int index, CursorListener listener) {
366 return new CursorImpl(index, listener);
367 }
368
369
370
371
372 @Override
373 public ByteArray slice(int index, int length) {
374 return cursor(index).slice(length);
375 }
376
377
378
379
380 @Override
381 public byte get(int index) {
382 return cursor(index).get();
383 }
384
385
386
387
388 @Override
389 public void put(int index, byte b) {
390 cursor(index).put(b);
391 }
392
393
394
395
396 @Override
397 public void get(int index, IoBuffer bb) {
398 cursor(index).get(bb);
399 }
400
401
402
403
404 @Override
405 public void put(int index, IoBuffer bb) {
406 cursor(index).put(bb);
407 }
408
409
410
411
412 @Override
413 public int first() {
414 return bas.firstByte();
415 }
416
417
418
419
420 @Override
421 public int last() {
422 return bas.lastByte();
423 }
424
425
426
427
428
429
430
431 private void addHook(ByteArray ba) {
432
433
434 if (ba.first() != 0) {
435 throw new IllegalArgumentException("Cannot add byte array that doesn't start from 0: " + ba.first());
436 }
437
438
439 if (order == null) {
440 order = ba.order();
441 } else if (!order.equals(ba.order())) {
442 throw new IllegalArgumentException("Cannot add byte array with different byte order: " + ba.order());
443 }
444 }
445
446
447
448
449 @Override
450 public ByteOrder order() {
451 if (order == null) {
452 throw new IllegalStateException("Byte order not yet set.");
453 }
454 return order;
455 }
456
457
458
459
460 @Override
461 public void order(ByteOrder order) {
462 if (order == null || !order.equals(this.order)) {
463 this.order = order;
464
465 if (!bas.isEmpty()) {
466 for (Node node = bas.getFirst(); node.hasNextNode(); node = node.getNextNode()) {
467 node.getByteArray().order(order);
468 }
469 }
470 }
471 }
472
473
474
475
476 @Override
477 public short getShort(int index) {
478 return cursor(index).getShort();
479 }
480
481
482
483
484 @Override
485 public void putShort(int index, short s) {
486 cursor(index).putShort(s);
487 }
488
489
490
491
492 @Override
493 public int getInt(int index) {
494 return cursor(index).getInt();
495 }
496
497
498
499
500 @Override
501 public void putInt(int index, int i) {
502 cursor(index).putInt(i);
503 }
504
505
506
507
508 @Override
509 public long getLong(int index) {
510 return cursor(index).getLong();
511 }
512
513
514
515
516 @Override
517 public void putLong(int index, long l) {
518 cursor(index).putLong(l);
519 }
520
521
522
523
524 @Override
525 public float getFloat(int index) {
526 return cursor(index).getFloat();
527 }
528
529
530
531
532 @Override
533 public void putFloat(int index, float f) {
534 cursor(index).putFloat(f);
535 }
536
537
538
539
540 @Override
541 public double getDouble(int index) {
542 return cursor(index).getDouble();
543 }
544
545
546
547
548 @Override
549 public void putDouble(int index, double d) {
550 cursor(index).putDouble(d);
551 }
552
553
554
555
556 @Override
557 public char getChar(int index) {
558 return cursor(index).getChar();
559 }
560
561
562
563
564 @Override
565 public void putChar(int index, char c) {
566 cursor(index).putChar(c);
567 }
568
569 private class CursorImpl implements Cursor {
570
571 private int index;
572
573 private final CursorListener listener;
574
575 private Node componentNode;
576
577
578 private int componentIndex;
579
580
581 private ByteArray.Cursor componentCursor;
582
583 public CursorImpl() {
584 this(0, null);
585 }
586
587 public CursorImpl(int index) {
588 this(index, null);
589 }
590
591 public CursorImpl(CursorListener listener) {
592 this(0, listener);
593 }
594
595 public CursorImpl(int index, CursorListener listener) {
596 this.index = index;
597 this.listener = listener;
598 }
599
600
601
602
603 @Override
604 public int getIndex() {
605 return index;
606 }
607
608
609
610
611 @Override
612 public void setIndex(int index) {
613 checkBounds(index, 0);
614 this.index = index;
615 }
616
617
618
619
620 @Override
621 public void skip(int length) {
622 setIndex(index + length);
623 }
624
625
626
627
628 @Override
629 public ByteArray slice(int length) {
630 CompositeByteArrayositeByteArray.html#CompositeByteArray">CompositeByteArray slice = new CompositeByteArray(byteArrayFactory);
631 int remaining = length;
632
633 while (remaining > 0) {
634 prepareForAccess(remaining);
635 int componentSliceSize = Math.min(remaining, componentCursor.getRemaining());
636 ByteArray componentSlice = componentCursor.slice(componentSliceSize);
637 slice.addLast(componentSlice);
638 index += componentSliceSize;
639 remaining -= componentSliceSize;
640 }
641
642 return slice;
643 }
644
645
646
647
648 @Override
649 public ByteOrder order() {
650 return CompositeByteArray.this.order();
651 }
652
653 private void prepareForAccess(int accessSize) {
654
655
656 if (componentNode != null && componentNode.isRemoved()) {
657 componentNode = null;
658 componentCursor = null;
659 }
660
661
662 checkBounds(index, accessSize);
663
664
665
666 Node oldComponentNode = componentNode;
667
668
669 if (componentNode == null) {
670 int basMidpoint = (last() - first()) / 2 + first();
671
672 if (index <= basMidpoint) {
673
674 componentNode = bas.getFirst();
675 componentIndex = first();
676
677 if (listener != null) {
678 listener.enteredFirstComponent(componentIndex, componentNode.getByteArray());
679 }
680 } else {
681
682 componentNode = bas.getLast();
683 componentIndex = last() - componentNode.getByteArray().last();
684
685 if (listener != null) {
686 listener.enteredLastComponent(componentIndex, componentNode.getByteArray());
687 }
688 }
689 }
690
691
692 while (index < componentIndex) {
693 componentNode = componentNode.getPreviousNode();
694 componentIndex -= componentNode.getByteArray().last();
695
696 if (listener != null) {
697 listener.enteredPreviousComponent(componentIndex, componentNode.getByteArray());
698 }
699 }
700
701
702 while (index >= componentIndex + componentNode.getByteArray().length()) {
703 componentIndex += componentNode.getByteArray().last();
704 componentNode = componentNode.getNextNode();
705
706 if (listener != null) {
707 listener.enteredNextComponent(componentIndex, componentNode.getByteArray());
708 }
709 }
710
711
712 int internalComponentIndex = index - componentIndex;
713
714 if (componentNode == oldComponentNode) {
715
716 componentCursor.setIndex(internalComponentIndex);
717 } else {
718
719 componentCursor = componentNode.getByteArray().cursor(internalComponentIndex);
720 }
721 }
722
723
724
725
726 @Override
727 public int getRemaining() {
728 return last() - index + 1;
729 }
730
731
732
733
734 @Override
735 public boolean hasRemaining() {
736 return getRemaining() > 0;
737 }
738
739
740
741
742 @Override
743 public byte get() {
744 prepareForAccess(1);
745 byte b = componentCursor.get();
746 index += 1;
747
748 return b;
749 }
750
751
752
753
754 @Override
755 public void put(byte b) {
756 prepareForAccess(1);
757 componentCursor.put(b);
758 index += 1;
759 }
760
761
762
763
764 @Override
765 public void get(IoBuffer bb) {
766 while (bb.hasRemaining()) {
767 int remainingBefore = bb.remaining();
768 prepareForAccess(remainingBefore);
769 componentCursor.get(bb);
770 int remainingAfter = bb.remaining();
771
772
773 int chunkSize = remainingBefore - remainingAfter;
774 index += chunkSize;
775 }
776 }
777
778
779
780
781 @Override
782 public void put(IoBuffer bb) {
783 while (bb.hasRemaining()) {
784 int remainingBefore = bb.remaining();
785 prepareForAccess(remainingBefore);
786 componentCursor.put(bb);
787 int remainingAfter = bb.remaining();
788
789
790 int chunkSize = remainingBefore - remainingAfter;
791 index += chunkSize;
792 }
793 }
794
795
796
797
798 @Override
799 public short getShort() {
800 prepareForAccess(2);
801
802 if (componentCursor.getRemaining() >= 4) {
803 short s = componentCursor.getShort();
804 index += 2;
805
806 return s;
807 } else {
808 byte b0 = get();
809 byte b1 = get();
810
811 if (order.equals(ByteOrder.BIG_ENDIAN)) {
812 return (short) ((b0 << 8) | (b1 & 0xFF));
813 } else {
814 return (short) ((b1 << 8) | (b0 & 0xFF));
815 }
816 }
817 }
818
819
820
821
822 @Override
823 public void putShort(short s) {
824 prepareForAccess(2);
825
826 if (componentCursor.getRemaining() >= 4) {
827 componentCursor.putShort(s);
828 index += 2;
829 } else {
830 if (order.equals(ByteOrder.BIG_ENDIAN)) {
831 put((byte) ((s >> 8) & 0xff));
832 put((byte) (s & 0xff));
833 } else {
834 put((byte) (s & 0xff));
835 put((byte) ((s >> 8) & 0xff));
836 }
837 }
838 }
839
840
841
842
843 @Override
844 public int getInt() {
845 prepareForAccess(4);
846
847 if (componentCursor.getRemaining() >= 4) {
848 int i = componentCursor.getInt();
849 index += 4;
850
851 return i;
852 } else {
853 byte b0 = get();
854 byte b1 = get();
855 byte b2 = get();
856 byte b3 = get();
857
858 if (order.equals(ByteOrder.BIG_ENDIAN)) {
859 return (b0 << 24) | ((b1 & 0xFF) << 16) | ((b2 & 0xFF) << 8) | (b3 & 0xFF);
860 } else {
861 return (b3 << 24) | ((b2 & 0xFF) << 16) | ((b1 & 0xFF) << 8) | (b0 & 0xFF);
862 }
863 }
864 }
865
866
867
868
869 @Override
870 public void putInt(int i) {
871 prepareForAccess(4);
872
873 if (componentCursor.getRemaining() >= 4) {
874 componentCursor.putInt(i);
875 index += 4;
876 } else {
877 if (order.equals(ByteOrder.BIG_ENDIAN)) {
878 put((byte) ((i >> 24) & 0xff));
879 put((byte) ((i >> 16) & 0xff));
880 put((byte) ((i >> 8) & 0xff));
881 put((byte) (i & 0xff));
882 } else {
883 put((byte) (i & 0xff));
884 put((byte) ((i >> 8) & 0xff));
885 put((byte) ((i >> 16) & 0xff));
886 put((byte) ((i >> 24) & 0xff));
887 }
888 }
889 }
890
891
892
893
894 @Override
895 public long getLong() {
896 prepareForAccess(8);
897
898 if (componentCursor.getRemaining() >= 4) {
899 long l = componentCursor.getLong();
900 index += 8;
901
902 return l;
903 } else {
904 byte b0 = get();
905 byte b1 = get();
906 byte b2 = get();
907 byte b3 = get();
908 byte b4 = get();
909 byte b5 = get();
910 byte b6 = get();
911 byte b7 = get();
912
913 if (order.equals(ByteOrder.BIG_ENDIAN)) {
914 return ((b0 & 0xFFL) << 56) | ((b1 & 0xFFL) << 48) | ((b2 & 0xFFL) << 40) | ((b3 & 0xFFL) << 32)
915 | ((b4 & 0xFFL) << 24) | ((b5 & 0xFFL) << 16) | ((b6 & 0xFFL) << 8) | (b7 & 0xFFL);
916 } else {
917 return ((b7 & 0xFFL) << 56) | ((b6 & 0xFFL) << 48) | ((b5 & 0xFFL) << 40) | ((b4 & 0xFFL) << 32)
918 | ((b3 & 0xFFL) << 24) | ((b2 & 0xFFL) << 16) | ((b1 & 0xFFL) << 8) | (b0 & 0xFFL);
919 }
920 }
921 }
922
923
924
925
926 @Override
927 public void putLong(long l) {
928 prepareForAccess(8);
929
930 if (componentCursor.getRemaining() >= 4) {
931 componentCursor.putLong(l);
932 index += 8;
933 } else {
934 if (order.equals(ByteOrder.BIG_ENDIAN)) {
935 put((byte) ((l >> 56) & 0xff));
936 put((byte) ((l >> 48) & 0xff));
937 put((byte) ((l >> 40) & 0xff));
938 put((byte) ((l >> 32) & 0xff));
939 put((byte) ((l >> 24) & 0xff));
940 put((byte) ((l >> 16) & 0xff));
941 put((byte) ((l >> 8) & 0xff));
942 put((byte) (l & 0xff));
943 } else {
944 put((byte) (l & 0xff));
945 put((byte) ((l >> 8) & 0xff));
946 put((byte) ((l >> 16) & 0xff));
947 put((byte) ((l >> 24) & 0xff));
948 put((byte) ((l >> 32) & 0xff));
949 put((byte) ((l >> 40) & 0xff));
950 put((byte) ((l >> 48) & 0xff));
951 put((byte) ((l >> 56) & 0xff));
952 }
953 }
954 }
955
956
957
958
959 @Override
960 public float getFloat() {
961 prepareForAccess(4);
962
963 if (componentCursor.getRemaining() >= 4) {
964 float f = componentCursor.getFloat();
965 index += 4;
966 return f;
967 } else {
968 int i = getInt();
969
970 return Float.intBitsToFloat(i);
971 }
972 }
973
974
975
976
977 @Override
978 public void putFloat(float f) {
979 prepareForAccess(4);
980
981 if (componentCursor.getRemaining() >= 4) {
982 componentCursor.putFloat(f);
983 index += 4;
984 } else {
985 int i = Float.floatToIntBits(f);
986 putInt(i);
987 }
988 }
989
990
991
992
993 @Override
994 public double getDouble() {
995 prepareForAccess(8);
996
997 if (componentCursor.getRemaining() >= 4) {
998 double d = componentCursor.getDouble();
999 index += 8;
1000
1001 return d;
1002 } else {
1003 long l = getLong();
1004
1005 return Double.longBitsToDouble(l);
1006 }
1007 }
1008
1009
1010
1011
1012 @Override
1013 public void putDouble(double d) {
1014 prepareForAccess(8);
1015
1016 if (componentCursor.getRemaining() >= 4) {
1017 componentCursor.putDouble(d);
1018 index += 8;
1019 } else {
1020 long l = Double.doubleToLongBits(d);
1021 putLong(l);
1022 }
1023 }
1024
1025
1026
1027
1028 @Override
1029 public char getChar() {
1030 prepareForAccess(2);
1031
1032 if (componentCursor.getRemaining() >= 4) {
1033 char c = componentCursor.getChar();
1034 index += 2;
1035
1036 return c;
1037 } else {
1038 byte b0 = get();
1039 byte b1 = get();
1040
1041 if (order.equals(ByteOrder.BIG_ENDIAN)) {
1042 return (char)((b0 << 8) | (b1 & 0xFF));
1043 } else {
1044 return (char)((b1 << 8) | (b0 & 0xFF));
1045 }
1046 }
1047 }
1048
1049
1050
1051
1052 @Override
1053 public void putChar(char c) {
1054 prepareForAccess(2);
1055
1056
1057 if (componentCursor.getRemaining() >= 4) {
1058 componentCursor.putChar(c);
1059 index += 2;
1060 } else {
1061 byte b0;
1062 byte b1;
1063
1064 if (order.equals(ByteOrder.BIG_ENDIAN)) {
1065 b0 = (byte) ((c >> 8) & 0xff);
1066 b1 = (byte) (c & 0xff);
1067 } else {
1068 b0 = (byte) (c & 0xff);
1069 b1 = (byte) ((c >> 8) & 0xff);
1070 }
1071
1072 put(b0);
1073 put(b1);
1074 }
1075 }
1076
1077 private void checkBounds(int index, int accessSize) {
1078 int lower = index;
1079 int upper = index + accessSize;
1080
1081 if (lower < first()) {
1082 throw new IndexOutOfBoundsException("Index " + lower + " less than start " + first() + ".");
1083 }
1084
1085 if (upper > last()) {
1086 throw new IndexOutOfBoundsException("Index " + upper + " greater than length " + last() + ".");
1087 }
1088 }
1089 }
1090
1091
1092
1093
1094
1095 @Override
1096 public int hashCode() {
1097 int h = 17;
1098
1099 h = h*37 + bas.hashCode();
1100
1101 return h;
1102 }
1103 }