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