1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.buffer;
17
18 import org.jboss.netty.util.internal.DetectionUtil;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.nio.ByteBuffer;
24 import java.nio.ByteOrder;
25 import java.nio.channels.GatheringByteChannel;
26 import java.nio.channels.ScatteringByteChannel;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.List;
30
31
32
33
34
35
36 public class CompositeChannelBuffer extends AbstractChannelBuffer {
37
38 private final ByteOrder order;
39 private ChannelBuffer[] components;
40 private int[] indices;
41 private int lastAccessedComponentId;
42 private final boolean gathering;
43
44 public CompositeChannelBuffer(ByteOrder endianness, List<ChannelBuffer> buffers, boolean gathering) {
45 order = endianness;
46 this.gathering = gathering;
47 setComponents(buffers);
48 }
49
50
51
52
53
54 public boolean useGathering() {
55 return gathering && DetectionUtil.javaVersion() >= 7;
56 }
57
58
59
60
61 public List<ChannelBuffer> decompose(int index, int length) {
62 if (length == 0) {
63 return Collections.emptyList();
64 }
65
66 if (index + length > capacity()) {
67 throw new IndexOutOfBoundsException("Too many bytes to decompose - Need "
68 + (index + length) + ", capacity is " + capacity());
69 }
70
71 int componentId = componentId(index);
72 List<ChannelBuffer> slice = new ArrayList<ChannelBuffer>(components.length);
73
74
75 ChannelBuffer first = components[componentId].duplicate();
76 first.readerIndex(index - indices[componentId]);
77
78 ChannelBuffer buf = first;
79 int bytesToSlice = length;
80 do {
81 int readableBytes = buf.readableBytes();
82 if (bytesToSlice <= readableBytes) {
83
84 buf.writerIndex(buf.readerIndex() + bytesToSlice);
85 slice.add(buf);
86 break;
87 } else {
88
89 slice.add(buf);
90 bytesToSlice -= readableBytes;
91 componentId ++;
92
93
94 buf = components[componentId].duplicate();
95 }
96 } while (bytesToSlice > 0);
97
98
99 for (int i = 0; i < slice.size(); i ++) {
100 slice.set(i, slice.get(i).slice());
101 }
102
103 return slice;
104 }
105
106
107
108
109 private void setComponents(List<ChannelBuffer> newComponents) {
110 assert !newComponents.isEmpty();
111
112
113 lastAccessedComponentId = 0;
114
115
116 components = new ChannelBuffer[newComponents.size()];
117 for (int i = 0; i < components.length; i ++) {
118 ChannelBuffer c = newComponents.get(i);
119 if (c.order() != order()) {
120 throw new IllegalArgumentException(
121 "All buffers must have the same endianness.");
122 }
123
124 assert c.readerIndex() == 0;
125 assert c.writerIndex() == c.capacity();
126
127 components[i] = c;
128 }
129
130
131 indices = new int[components.length + 1];
132 indices[0] = 0;
133 for (int i = 1; i <= components.length; i ++) {
134 indices[i] = indices[i - 1] + components[i - 1].capacity();
135 }
136
137
138 setIndex(0, capacity());
139 }
140
141 private CompositeChannelBuffer(CompositeChannelBuffer buffer) {
142 order = buffer.order;
143 gathering = buffer.gathering;
144 components = buffer.components.clone();
145 indices = buffer.indices.clone();
146 setIndex(buffer.readerIndex(), buffer.writerIndex());
147 }
148
149 public ChannelBufferFactory factory() {
150 return HeapChannelBufferFactory.getInstance(order());
151 }
152
153 public ByteOrder order() {
154 return order;
155 }
156
157 public boolean isDirect() {
158 return false;
159 }
160
161 public boolean hasArray() {
162 return false;
163 }
164
165 public byte[] array() {
166 throw new UnsupportedOperationException();
167 }
168
169 public int arrayOffset() {
170 throw new UnsupportedOperationException();
171 }
172
173 public int capacity() {
174 return indices[components.length];
175 }
176
177 public int numComponents() {
178 return components.length;
179 }
180
181 public byte getByte(int index) {
182 int componentId = componentId(index);
183 return components[componentId].getByte(index - indices[componentId]);
184 }
185
186 public short getShort(int index) {
187 int componentId = componentId(index);
188 if (index + 2 <= indices[componentId + 1]) {
189 return components[componentId].getShort(index - indices[componentId]);
190 } else if (order() == ByteOrder.BIG_ENDIAN) {
191 return (short) ((getByte(index) & 0xff) << 8 | getByte(index + 1) & 0xff);
192 } else {
193 return (short) (getByte(index) & 0xff | (getByte(index + 1) & 0xff) << 8);
194 }
195 }
196
197 public int getUnsignedMedium(int index) {
198 int componentId = componentId(index);
199 if (index + 3 <= indices[componentId + 1]) {
200 return components[componentId].getUnsignedMedium(index - indices[componentId]);
201 } else if (order() == ByteOrder.BIG_ENDIAN) {
202 return (getShort(index) & 0xffff) << 8 | getByte(index + 2) & 0xff;
203 } else {
204 return getShort(index) & 0xFFFF | (getByte(index + 2) & 0xFF) << 16;
205 }
206 }
207
208 public int getInt(int index) {
209 int componentId = componentId(index);
210 if (index + 4 <= indices[componentId + 1]) {
211 return components[componentId].getInt(index - indices[componentId]);
212 } else if (order() == ByteOrder.BIG_ENDIAN) {
213 return (getShort(index) & 0xffff) << 16 | getShort(index + 2) & 0xffff;
214 } else {
215 return getShort(index) & 0xFFFF | (getShort(index + 2) & 0xFFFF) << 16;
216 }
217 }
218
219 public long getLong(int index) {
220 int componentId = componentId(index);
221 if (index + 8 <= indices[componentId + 1]) {
222 return components[componentId].getLong(index - indices[componentId]);
223 } else if (order() == ByteOrder.BIG_ENDIAN) {
224 return (getInt(index) & 0xffffffffL) << 32 | getInt(index + 4) & 0xffffffffL;
225 } else {
226 return getInt(index) & 0xFFFFFFFFL | (getInt(index + 4) & 0xFFFFFFFFL) << 32;
227 }
228 }
229
230 public void getBytes(int index, byte[] dst, int dstIndex, int length) {
231 if (index > capacity() - length || dstIndex > dst.length - length) {
232 throw new IndexOutOfBoundsException("Too many bytes to read - Needs "
233 + (index + length) + ", maximum is " + capacity() + " or "
234 + dst.length);
235 }
236 if (index < 0) {
237 throw new IndexOutOfBoundsException("Index must be >= 0");
238 }
239 if (length == 0) {
240 return;
241 }
242
243 int componentId = componentId(index);
244
245 int i = componentId;
246 while (length > 0) {
247 ChannelBuffer s = components[i];
248 int adjustment = indices[i];
249 int localLength = Math.min(length, s.capacity() - (index - adjustment));
250 s.getBytes(index - adjustment, dst, dstIndex, localLength);
251 index += localLength;
252 dstIndex += localLength;
253 length -= localLength;
254 i ++;
255 }
256 }
257
258 public void getBytes(int index, ByteBuffer dst) {
259 int componentId = componentId(index);
260 int limit = dst.limit();
261 int length = dst.remaining();
262 if (index > capacity() - length) {
263 throw new IndexOutOfBoundsException("Too many bytes to be read - Needs "
264 + (index + length) + ", maximum is " + capacity());
265 }
266 if (index < 0) {
267 throw new IndexOutOfBoundsException("Index must be >= 0");
268 }
269 int i = componentId;
270 try {
271 while (length > 0) {
272 ChannelBuffer s = components[i];
273 int adjustment = indices[i];
274 int localLength = Math.min(length, s.capacity() - (index - adjustment));
275 dst.limit(dst.position() + localLength);
276 s.getBytes(index - adjustment, dst);
277 index += localLength;
278 length -= localLength;
279 i ++;
280 }
281 } finally {
282 dst.limit(limit);
283 }
284 }
285
286 public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {
287 if (index > capacity() - length || dstIndex > dst.capacity() - length) {
288 throw new IndexOutOfBoundsException("Too many bytes to be read - Needs "
289 + (index + length) + " or " + (dstIndex + length) + ", maximum is "
290 + capacity() + " or " + dst.capacity());
291 }
292 if (index < 0) {
293 throw new IndexOutOfBoundsException("Index must be >= 0");
294 }
295 if (length == 0) {
296 return;
297 }
298 int i = componentId(index);
299 while (length > 0) {
300 ChannelBuffer s = components[i];
301 int adjustment = indices[i];
302 int localLength = Math.min(length, s.capacity() - (index - adjustment));
303 s.getBytes(index - adjustment, dst, dstIndex, localLength);
304 index += localLength;
305 dstIndex += localLength;
306 length -= localLength;
307 i ++;
308 }
309 }
310
311 public int getBytes(int index, GatheringByteChannel out, int length)
312 throws IOException {
313
314 if (useGathering()) {
315 return (int) out.write(toByteBuffers(index, length));
316 }
317
318
319
320
321 return out.write(toByteBuffer(index, length));
322 }
323
324 public void getBytes(int index, OutputStream out, int length)
325 throws IOException {
326 if (index > capacity() - length) {
327 throw new IndexOutOfBoundsException("Too many bytes to be read - needs "
328 + (index + length) + ", maximum of " + capacity());
329 }
330 if (index < 0) {
331 throw new IndexOutOfBoundsException("Index must be >= 0");
332 }
333 if (length == 0) {
334 return;
335 }
336 int i = componentId(index);
337 while (length > 0) {
338 ChannelBuffer s = components[i];
339 int adjustment = indices[i];
340 int localLength = Math.min(length, s.capacity() - (index - adjustment));
341 s.getBytes(index - adjustment, out, localLength);
342 index += localLength;
343 length -= localLength;
344 i ++;
345 }
346 }
347
348 public void setByte(int index, int value) {
349 int componentId = componentId(index);
350 components[componentId].setByte(index - indices[componentId], value);
351 }
352
353 public void setShort(int index, int value) {
354 int componentId = componentId(index);
355 if (index + 2 <= indices[componentId + 1]) {
356 components[componentId].setShort(index - indices[componentId], value);
357 } else if (order() == ByteOrder.BIG_ENDIAN) {
358 setByte(index, (byte) (value >>> 8));
359 setByte(index + 1, (byte) value);
360 } else {
361 setByte(index , (byte) value);
362 setByte(index + 1, (byte) (value >>> 8));
363 }
364 }
365
366 public void setMedium(int index, int value) {
367 int componentId = componentId(index);
368 if (index + 3 <= indices[componentId + 1]) {
369 components[componentId].setMedium(index - indices[componentId], value);
370 } else if (order() == ByteOrder.BIG_ENDIAN) {
371 setShort(index, (short) (value >> 8));
372 setByte(index + 2, (byte) value);
373 } else {
374 setShort(index , (short) value);
375 setByte(index + 2, (byte) (value >>> 16));
376 }
377 }
378
379 public void setInt(int index, int value) {
380 int componentId = componentId(index);
381 if (index + 4 <= indices[componentId + 1]) {
382 components[componentId].setInt(index - indices[componentId], value);
383 } else if (order() == ByteOrder.BIG_ENDIAN) {
384 setShort(index, (short) (value >>> 16));
385 setShort(index + 2, (short) value);
386 } else {
387 setShort(index , (short) value);
388 setShort(index + 2, (short) (value >>> 16));
389 }
390 }
391
392 public void setLong(int index, long value) {
393 int componentId = componentId(index);
394 if (index + 8 <= indices[componentId + 1]) {
395 components[componentId].setLong(index - indices[componentId], value);
396 } else if (order() == ByteOrder.BIG_ENDIAN) {
397 setInt(index, (int) (value >>> 32));
398 setInt(index + 4, (int) value);
399 } else {
400 setInt(index , (int) value);
401 setInt(index + 4, (int) (value >>> 32));
402 }
403 }
404
405 public void setBytes(int index, byte[] src, int srcIndex, int length) {
406 int componentId = componentId(index);
407 if (index > capacity() - length || srcIndex > src.length - length) {
408 throw new IndexOutOfBoundsException("Too many bytes to read - needs "
409 + (index + length) + " or " + (srcIndex + length) + ", maximum is "
410 + capacity() + " or " + src.length);
411 }
412
413 int i = componentId;
414 while (length > 0) {
415 ChannelBuffer s = components[i];
416 int adjustment = indices[i];
417 int localLength = Math.min(length, s.capacity() - (index - adjustment));
418 s.setBytes(index - adjustment, src, srcIndex, localLength);
419 index += localLength;
420 srcIndex += localLength;
421 length -= localLength;
422 i ++;
423 }
424 }
425
426 public void setBytes(int index, ByteBuffer src) {
427 int componentId = componentId(index);
428 int limit = src.limit();
429 int length = src.remaining();
430 if (index > capacity() - length) {
431 throw new IndexOutOfBoundsException("Too many bytes to be written - Needs "
432 + (index + length) + ", maximum is " + capacity());
433 }
434
435 int i = componentId;
436 try {
437 while (length > 0) {
438 ChannelBuffer s = components[i];
439 int adjustment = indices[i];
440 int localLength = Math.min(length, s.capacity() - (index - adjustment));
441 src.limit(src.position() + localLength);
442 s.setBytes(index - adjustment, src);
443 index += localLength;
444 length -= localLength;
445 i ++;
446 }
447 } finally {
448 src.limit(limit);
449 }
450 }
451
452 public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {
453 int componentId = componentId(index);
454 if (index > capacity() - length || srcIndex > src.capacity() - length) {
455 throw new IndexOutOfBoundsException("Too many bytes to be written - Needs "
456 + (index + length) + " or " + (srcIndex + length) + ", maximum is "
457 + capacity() + " or " + src.capacity());
458 }
459
460 int i = componentId;
461 while (length > 0) {
462 ChannelBuffer s = components[i];
463 int adjustment = indices[i];
464 int localLength = Math.min(length, s.capacity() - (index - adjustment));
465 s.setBytes(index - adjustment, src, srcIndex, localLength);
466 index += localLength;
467 srcIndex += localLength;
468 length -= localLength;
469 i ++;
470 }
471 }
472
473 public int setBytes(int index, InputStream in, int length)
474 throws IOException {
475 int componentId = componentId(index);
476 if (index > capacity() - length) {
477 throw new IndexOutOfBoundsException("Too many bytes to write - Needs "
478 + (index + length) + ", maximum is " + capacity());
479 }
480
481 int i = componentId;
482 int readBytes = 0;
483
484 do {
485 ChannelBuffer s = components[i];
486 int adjustment = indices[i];
487 int localLength = Math.min(length, s.capacity() - (index - adjustment));
488 int localReadBytes = s.setBytes(index - adjustment, in, localLength);
489 if (localReadBytes < 0) {
490 if (readBytes == 0) {
491 return -1;
492 } else {
493 break;
494 }
495 }
496
497 if (localReadBytes == localLength) {
498 index += localLength;
499 length -= localLength;
500 readBytes += localLength;
501 i ++;
502 } else {
503 index += localReadBytes;
504 length -= localReadBytes;
505 readBytes += localReadBytes;
506 }
507 } while (length > 0);
508
509 return readBytes;
510 }
511
512 public int setBytes(int index, ScatteringByteChannel in, int length)
513 throws IOException {
514 int componentId = componentId(index);
515 if (index > capacity() - length) {
516 throw new IndexOutOfBoundsException("Too many bytes to write - Needs "
517 + (index + length) + ", maximum is " + capacity());
518 }
519
520 int i = componentId;
521 int readBytes = 0;
522 do {
523 ChannelBuffer s = components[i];
524 int adjustment = indices[i];
525 int localLength = Math.min(length, s.capacity() - (index - adjustment));
526 int localReadBytes = s.setBytes(index - adjustment, in, localLength);
527
528 if (localReadBytes == 0) {
529 break;
530 }
531
532 if (localReadBytes < 0) {
533 if (readBytes == 0) {
534 return -1;
535 } else {
536 break;
537 }
538 }
539
540 if (localReadBytes == localLength) {
541 index += localLength;
542 length -= localLength;
543 readBytes += localLength;
544 i ++;
545 } else {
546 index += localReadBytes;
547 length -= localReadBytes;
548 readBytes += localReadBytes;
549 }
550 } while (length > 0);
551
552 return readBytes;
553 }
554
555 public ChannelBuffer duplicate() {
556 ChannelBuffer duplicate = new CompositeChannelBuffer(this);
557 duplicate.setIndex(readerIndex(), writerIndex());
558 return duplicate;
559 }
560
561 public ChannelBuffer copy(int index, int length) {
562 int componentId = componentId(index);
563 if (index > capacity() - length) {
564 throw new IndexOutOfBoundsException("Too many bytes to copy - Needs "
565 + (index + length) + ", maximum is " + capacity());
566 }
567
568 ChannelBuffer dst = factory().getBuffer(order(), length);
569 copyTo(index, length, componentId, dst);
570 return dst;
571 }
572
573 private void copyTo(int index, int length, int componentId, ChannelBuffer dst) {
574 int dstIndex = 0;
575 int i = componentId;
576
577 while (length > 0) {
578 ChannelBuffer s = components[i];
579 int adjustment = indices[i];
580 int localLength = Math.min(length, s.capacity() - (index - adjustment));
581 s.getBytes(index - adjustment, dst, dstIndex, localLength);
582 index += localLength;
583 dstIndex += localLength;
584 length -= localLength;
585 i ++;
586 }
587
588 dst.writerIndex(dst.capacity());
589 }
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608 public ChannelBuffer getBuffer(int index) {
609 if (index < 0 || index >= capacity()) {
610 throw new IndexOutOfBoundsException("Invalid index: " + index
611 + " - Bytes needed: " + index + ", maximum is "
612 + capacity());
613 }
614
615
616 return components[componentId(index)];
617
618 }
619
620 public ChannelBuffer slice(int index, int length) {
621 if (index == 0) {
622 if (length == 0) {
623 return ChannelBuffers.EMPTY_BUFFER;
624 }
625 } else if (index < 0 || index > capacity() - length) {
626 throw new IndexOutOfBoundsException("Invalid index: " + index
627 + " - Bytes needed: " + (index + length) + ", maximum is "
628 + capacity());
629 } else if (length == 0) {
630 return ChannelBuffers.EMPTY_BUFFER;
631 }
632
633 List<ChannelBuffer> components = decompose(index, length);
634 switch (components.size()) {
635 case 0:
636 return ChannelBuffers.EMPTY_BUFFER;
637 case 1:
638 return components.get(0);
639 default:
640 return new CompositeChannelBuffer(order(), components, gathering);
641 }
642 }
643
644 public ByteBuffer toByteBuffer(int index, int length) {
645 if (components.length == 1) {
646 return components[0].toByteBuffer(index, length);
647 }
648
649 ByteBuffer[] buffers = toByteBuffers(index, length);
650 ByteBuffer merged = ByteBuffer.allocate(length).order(order());
651 for (ByteBuffer b: buffers) {
652 merged.put(b);
653 }
654 merged.flip();
655 return merged;
656 }
657
658 @Override
659 public ByteBuffer[] toByteBuffers(int index, int length) {
660 if (index + length > capacity()) {
661 throw new IndexOutOfBoundsException("Too many bytes to convert - Needs"
662 + (index + length) + ", maximum is " + capacity());
663 }
664 if (index < 0) {
665 throw new IndexOutOfBoundsException("Index must be >= 0");
666 }
667 if (length == 0) {
668 return new ByteBuffer[0];
669 }
670
671 List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(components.length);
672
673 int i = componentId(index);
674 while (length > 0) {
675 ChannelBuffer s = components[i];
676 int adjustment = indices[i];
677 int localLength = Math.min(length, s.capacity() - (index - adjustment));
678 buffers.add(s.toByteBuffer(index - adjustment, localLength));
679 index += localLength;
680 length -= localLength;
681 i ++;
682 }
683
684 return buffers.toArray(new ByteBuffer[buffers.size()]);
685 }
686
687 private int componentId(int index) {
688 int lastComponentId = lastAccessedComponentId;
689 if (index >= indices[lastComponentId]) {
690 if (index < indices[lastComponentId + 1]) {
691 return lastComponentId;
692 }
693
694
695 for (int i = lastComponentId + 1; i < components.length; i ++) {
696 if (index < indices[i + 1]) {
697 lastAccessedComponentId = i;
698 return i;
699 }
700 }
701 } else {
702
703 for (int i = lastComponentId - 1; i >= 0; i --) {
704 if (index >= indices[i]) {
705 lastAccessedComponentId = i;
706 return i;
707 }
708 }
709 }
710
711 throw new IndexOutOfBoundsException("Invalid index: " + index + ", maximum: " + indices.length);
712 }
713
714 @Override
715 public void discardReadBytes() {
716
717
718
719
720 final int localReaderIndex = readerIndex();
721 if (localReaderIndex == 0) {
722 return;
723 }
724 int localWriterIndex = writerIndex();
725
726 final int bytesToMove = capacity() - localReaderIndex;
727 List<ChannelBuffer> list = decompose(localReaderIndex, bytesToMove);
728
729
730
731
732
733 if (list.isEmpty()) {
734 list = new ArrayList<ChannelBuffer>(1);
735 }
736
737
738
739 final ChannelBuffer padding = ChannelBuffers.buffer(order(), localReaderIndex);
740 padding.writerIndex(localReaderIndex);
741 list.add(padding);
742
743
744 int localMarkedReaderIndex = localReaderIndex;
745 try {
746 resetReaderIndex();
747 localMarkedReaderIndex = readerIndex();
748 } catch (IndexOutOfBoundsException e) {
749
750 }
751 int localMarkedWriterIndex = localWriterIndex;
752 try {
753 resetWriterIndex();
754 localMarkedWriterIndex = writerIndex();
755 } catch (IndexOutOfBoundsException e) {
756
757 }
758
759 setComponents(list);
760
761
762 localMarkedReaderIndex = Math.max(localMarkedReaderIndex - localReaderIndex, 0);
763 localMarkedWriterIndex = Math.max(localMarkedWriterIndex - localReaderIndex, 0);
764 setIndex(localMarkedReaderIndex, localMarkedWriterIndex);
765 markReaderIndex();
766 markWriterIndex();
767
768 localWriterIndex = Math.max(localWriterIndex - localReaderIndex, 0);
769 setIndex(0, localWriterIndex);
770 }
771
772 @Override
773 public String toString() {
774 String result = super.toString();
775 result = result.substring(0, result.length() - 1);
776 return result + ", components=" + components.length + ')';
777 }
778 }