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