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