1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.buffer;
17
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.OutputStream;
21 import java.nio.ByteBuffer;
22 import java.nio.ByteOrder;
23 import java.nio.channels.GatheringByteChannel;
24 import java.nio.channels.ScatteringByteChannel;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.List;
28
29 import org.jboss.netty.util.internal.DetectionUtil;
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 int componentId = componentId(index);
232 if (index > capacity() - length || dstIndex > dst.length - length) {
233 throw new IndexOutOfBoundsException("Too many bytes to read - Needs "
234 + (index + length) + ", maximum is " + capacity() + " or "
235 + dst.length);
236 }
237
238 int i = componentId;
239 while (length > 0) {
240 ChannelBuffer s = components[i];
241 int adjustment = indices[i];
242 int localLength = Math.min(length, s.capacity() - (index - adjustment));
243 s.getBytes(index - adjustment, dst, dstIndex, localLength);
244 index += localLength;
245 dstIndex += localLength;
246 length -= localLength;
247 i ++;
248 }
249 }
250
251 public void getBytes(int index, ByteBuffer dst) {
252 int componentId = componentId(index);
253 int limit = dst.limit();
254 int length = dst.remaining();
255 if (index > capacity() - length) {
256 throw new IndexOutOfBoundsException("Too many bytes to be read - Needs "
257 + (index + length) + ", maximum is " + capacity());
258 }
259
260 int i = componentId;
261 try {
262 while (length > 0) {
263 ChannelBuffer s = components[i];
264 int adjustment = indices[i];
265 int localLength = Math.min(length, s.capacity() - (index - adjustment));
266 dst.limit(dst.position() + localLength);
267 s.getBytes(index - adjustment, dst);
268 index += localLength;
269 length -= localLength;
270 i ++;
271 }
272 } finally {
273 dst.limit(limit);
274 }
275 }
276
277 public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {
278 int componentId = componentId(index);
279 if (index > capacity() - length || dstIndex > dst.capacity() - length) {
280 throw new IndexOutOfBoundsException("Too many bytes to be read - Needs "
281 + (index + length) + " or " + (dstIndex + length) + ", maximum is "
282 + capacity() + " or " + dst.capacity());
283 }
284
285 int i = componentId;
286 while (length > 0) {
287 ChannelBuffer s = components[i];
288 int adjustment = indices[i];
289 int localLength = Math.min(length, s.capacity() - (index - adjustment));
290 s.getBytes(index - adjustment, dst, dstIndex, localLength);
291 index += localLength;
292 dstIndex += localLength;
293 length -= localLength;
294 i ++;
295 }
296 }
297
298 public int getBytes(int index, GatheringByteChannel out, int length)
299 throws IOException {
300
301 if (useGathering()) {
302 return (int) out.write(toByteBuffers(index, length));
303 }
304
305
306
307
308 return out.write(toByteBuffer(index, length));
309 }
310
311 public void getBytes(int index, OutputStream out, int length)
312 throws IOException {
313 int componentId = componentId(index);
314 if (index > capacity() - length) {
315 throw new IndexOutOfBoundsException("Too many bytes to be read - needs "
316 + (index + length) + ", maximum of " + capacity());
317 }
318
319 int i = componentId;
320 while (length > 0) {
321 ChannelBuffer s = components[i];
322 int adjustment = indices[i];
323 int localLength = Math.min(length, s.capacity() - (index - adjustment));
324 s.getBytes(index - adjustment, out, localLength);
325 index += localLength;
326 length -= localLength;
327 i ++;
328 }
329 }
330
331 public void setByte(int index, int value) {
332 int componentId = componentId(index);
333 components[componentId].setByte(index - indices[componentId], value);
334 }
335
336 public void setShort(int index, int value) {
337 int componentId = componentId(index);
338 if (index + 2 <= indices[componentId + 1]) {
339 components[componentId].setShort(index - indices[componentId], value);
340 } else if (order() == ByteOrder.BIG_ENDIAN) {
341 setByte(index, (byte) (value >>> 8));
342 setByte(index + 1, (byte) value);
343 } else {
344 setByte(index , (byte) value);
345 setByte(index + 1, (byte) (value >>> 8));
346 }
347 }
348
349 public void setMedium(int index, int value) {
350 int componentId = componentId(index);
351 if (index + 3 <= indices[componentId + 1]) {
352 components[componentId].setMedium(index - indices[componentId], value);
353 } else if (order() == ByteOrder.BIG_ENDIAN) {
354 setShort(index, (short) (value >> 8));
355 setByte(index + 2, (byte) value);
356 } else {
357 setShort(index , (short) value);
358 setByte(index + 2, (byte) (value >>> 16));
359 }
360 }
361
362 public void setInt(int index, int value) {
363 int componentId = componentId(index);
364 if (index + 4 <= indices[componentId + 1]) {
365 components[componentId].setInt(index - indices[componentId], value);
366 } else if (order() == ByteOrder.BIG_ENDIAN) {
367 setShort(index, (short) (value >>> 16));
368 setShort(index + 2, (short) value);
369 } else {
370 setShort(index , (short) value);
371 setShort(index + 2, (short) (value >>> 16));
372 }
373 }
374
375 public void setLong(int index, long value) {
376 int componentId = componentId(index);
377 if (index + 8 <= indices[componentId + 1]) {
378 components[componentId].setLong(index - indices[componentId], value);
379 } else if (order() == ByteOrder.BIG_ENDIAN) {
380 setInt(index, (int) (value >>> 32));
381 setInt(index + 4, (int) value);
382 } else {
383 setInt(index , (int) value);
384 setInt(index + 4, (int) (value >>> 32));
385 }
386 }
387
388 public void setBytes(int index, byte[] src, int srcIndex, int length) {
389 int componentId = componentId(index);
390 if (index > capacity() - length || srcIndex > src.length - length) {
391 throw new IndexOutOfBoundsException("Too many bytes to read - needs "
392 + (index + length) + " or " + (srcIndex + length) + ", maximum is "
393 + capacity() + " or " + src.length);
394 }
395
396 int i = componentId;
397 while (length > 0) {
398 ChannelBuffer s = components[i];
399 int adjustment = indices[i];
400 int localLength = Math.min(length, s.capacity() - (index - adjustment));
401 s.setBytes(index - adjustment, src, srcIndex, localLength);
402 index += localLength;
403 srcIndex += localLength;
404 length -= localLength;
405 i ++;
406 }
407 }
408
409 public void setBytes(int index, ByteBuffer src) {
410 int componentId = componentId(index);
411 int limit = src.limit();
412 int length = src.remaining();
413 if (index > capacity() - length) {
414 throw new IndexOutOfBoundsException("Too many bytes to be written - Needs "
415 + (index + length) + ", maximum is " + capacity());
416 }
417
418 int i = componentId;
419 try {
420 while (length > 0) {
421 ChannelBuffer s = components[i];
422 int adjustment = indices[i];
423 int localLength = Math.min(length, s.capacity() - (index - adjustment));
424 src.limit(src.position() + localLength);
425 s.setBytes(index - adjustment, src);
426 index += localLength;
427 length -= localLength;
428 i ++;
429 }
430 } finally {
431 src.limit(limit);
432 }
433 }
434
435 public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {
436 int componentId = componentId(index);
437 if (index > capacity() - length || srcIndex > src.capacity() - length) {
438 throw new IndexOutOfBoundsException("Too many bytes to be written - Needs "
439 + (index + length) + " or " + (srcIndex + length) + ", maximum is "
440 + capacity() + " or " + src.capacity());
441 }
442
443 int i = componentId;
444 while (length > 0) {
445 ChannelBuffer s = components[i];
446 int adjustment = indices[i];
447 int localLength = Math.min(length, s.capacity() - (index - adjustment));
448 s.setBytes(index - adjustment, src, srcIndex, localLength);
449 index += localLength;
450 srcIndex += localLength;
451 length -= localLength;
452 i ++;
453 }
454 }
455
456 public int setBytes(int index, InputStream in, int length)
457 throws IOException {
458 int componentId = componentId(index);
459 if (index > capacity() - length) {
460 throw new IndexOutOfBoundsException("Too many bytes to write - Needs "
461 + (index + length) + ", maximum is " + capacity());
462 }
463
464 int i = componentId;
465 int readBytes = 0;
466
467 do {
468 ChannelBuffer s = components[i];
469 int adjustment = indices[i];
470 int localLength = Math.min(length, s.capacity() - (index - adjustment));
471 int localReadBytes = s.setBytes(index - adjustment, in, localLength);
472 if (localReadBytes < 0) {
473 if (readBytes == 0) {
474 return -1;
475 } else {
476 break;
477 }
478 }
479
480 if (localReadBytes == localLength) {
481 index += localLength;
482 length -= localLength;
483 readBytes += localLength;
484 i ++;
485 } else {
486 index += localReadBytes;
487 length -= localReadBytes;
488 readBytes += localReadBytes;
489 }
490 } while (length > 0);
491
492 return readBytes;
493 }
494
495 public int setBytes(int index, ScatteringByteChannel in, int length)
496 throws IOException {
497 int componentId = componentId(index);
498 if (index > capacity() - length) {
499 throw new IndexOutOfBoundsException("Too many bytes to write - Needs "
500 + (index + length) + ", maximum is " + capacity());
501 }
502
503 int i = componentId;
504 int readBytes = 0;
505 do {
506 ChannelBuffer s = components[i];
507 int adjustment = indices[i];
508 int localLength = Math.min(length, s.capacity() - (index - adjustment));
509 int localReadBytes = s.setBytes(index - adjustment, in, localLength);
510
511 if (localReadBytes == 0) {
512 break;
513 }
514
515 if (localReadBytes < 0) {
516 if (readBytes == 0) {
517 return -1;
518 } else {
519 break;
520 }
521 }
522
523 if (localReadBytes == localLength) {
524 index += localLength;
525 length -= localLength;
526 readBytes += localLength;
527 i ++;
528 } else {
529 index += localReadBytes;
530 length -= localReadBytes;
531 readBytes += localReadBytes;
532 }
533 } while (length > 0);
534
535 return readBytes;
536 }
537
538 public ChannelBuffer duplicate() {
539 ChannelBuffer duplicate = new CompositeChannelBuffer(this);
540 duplicate.setIndex(readerIndex(), writerIndex());
541 return duplicate;
542 }
543
544 public ChannelBuffer copy(int index, int length) {
545 int componentId = componentId(index);
546 if (index > capacity() - length) {
547 throw new IndexOutOfBoundsException("Too many bytes to copy - Needs "
548 + (index + length) + ", maximum is " + capacity());
549 }
550
551 ChannelBuffer dst = factory().getBuffer(order(), length);
552 copyTo(index, length, componentId, dst);
553 return dst;
554 }
555
556 private void copyTo(int index, int length, int componentId, ChannelBuffer dst) {
557 int dstIndex = 0;
558 int i = componentId;
559
560 while (length > 0) {
561 ChannelBuffer s = components[i];
562 int adjustment = indices[i];
563 int localLength = Math.min(length, s.capacity() - (index - adjustment));
564 s.getBytes(index - adjustment, dst, dstIndex, localLength);
565 index += localLength;
566 dstIndex += localLength;
567 length -= localLength;
568 i ++;
569 }
570
571 dst.writerIndex(dst.capacity());
572 }
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591 public ChannelBuffer getBuffer(int index) throws IndexOutOfBoundsException {
592 if (index < 0 || index >= capacity()) {
593 throw new IndexOutOfBoundsException("Invalid index: " + index
594 + " - Bytes needed: " + index + ", maximum is "
595 + capacity());
596 }
597
598
599 return components[componentId(index)];
600
601 }
602
603 public ChannelBuffer slice(int index, int length) {
604 if (index == 0) {
605 if (length == 0) {
606 return ChannelBuffers.EMPTY_BUFFER;
607 }
608 } else if (index < 0 || index > capacity() - length) {
609 throw new IndexOutOfBoundsException("Invalid index: " + index
610 + " - Bytes needed: " + (index + length) + ", maximum is "
611 + capacity());
612 } else if (length == 0) {
613 return ChannelBuffers.EMPTY_BUFFER;
614 }
615
616 List<ChannelBuffer> components = decompose(index, length);
617 switch (components.size()) {
618 case 0:
619 return ChannelBuffers.EMPTY_BUFFER;
620 case 1:
621 return components.get(0);
622 default:
623 return new CompositeChannelBuffer(order(), components, gathering);
624 }
625 }
626
627 public ByteBuffer toByteBuffer(int index, int length) {
628 if (components.length == 1) {
629 return components[0].toByteBuffer(index, length);
630 }
631
632 ByteBuffer[] buffers = toByteBuffers(index, length);
633 ByteBuffer merged = ByteBuffer.allocate(length).order(order());
634 for (ByteBuffer b: buffers) {
635 merged.put(b);
636 }
637 merged.flip();
638 return merged;
639 }
640
641 @Override
642 public ByteBuffer[] toByteBuffers(int index, int length) {
643 int componentId = componentId(index);
644 if (index + length > capacity()) {
645 throw new IndexOutOfBoundsException("Too many bytes to convert - Needs"
646 + (index + length) + ", maximum is " + capacity());
647 }
648
649 List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(components.length);
650
651 int i = componentId;
652 while (length > 0) {
653 ChannelBuffer s = components[i];
654 int adjustment = indices[i];
655 int localLength = Math.min(length, s.capacity() - (index - adjustment));
656 buffers.add(s.toByteBuffer(index - adjustment, localLength));
657 index += localLength;
658 length -= localLength;
659 i ++;
660 }
661
662 return buffers.toArray(new ByteBuffer[buffers.size()]);
663 }
664
665 private int componentId(int index) {
666 int lastComponentId = lastAccessedComponentId;
667 if (index >= indices[lastComponentId]) {
668 if (index < indices[lastComponentId + 1]) {
669 return lastComponentId;
670 }
671
672
673 for (int i = lastComponentId + 1; i < components.length; i ++) {
674 if (index < indices[i + 1]) {
675 lastAccessedComponentId = i;
676 return i;
677 }
678 }
679 } else {
680
681 for (int i = lastComponentId - 1; i >= 0; i --) {
682 if (index >= indices[i]) {
683 lastAccessedComponentId = i;
684 return i;
685 }
686 }
687 }
688
689 throw new IndexOutOfBoundsException("Invalid index: " + index + ", maximum: " + indices.length);
690 }
691
692 @Override
693 public void discardReadBytes() {
694
695
696
697
698 final int localReaderIndex = this.readerIndex();
699 if (localReaderIndex == 0) {
700 return;
701 }
702 int localWriterIndex = this.writerIndex();
703
704 final int bytesToMove = capacity() - localReaderIndex;
705 List<ChannelBuffer> list = decompose(localReaderIndex, bytesToMove);
706
707
708
709
710
711 if (list.isEmpty()) {
712 list = new ArrayList<ChannelBuffer>(1);
713 }
714
715
716
717 final ChannelBuffer padding = ChannelBuffers.buffer(order(), localReaderIndex);
718 padding.writerIndex(localReaderIndex);
719 list.add(padding);
720
721
722 int localMarkedReaderIndex = localReaderIndex;
723 try {
724 resetReaderIndex();
725 localMarkedReaderIndex = this.readerIndex();
726 } catch (IndexOutOfBoundsException e) {
727
728 }
729 int localMarkedWriterIndex = localWriterIndex;
730 try {
731 resetWriterIndex();
732 localMarkedWriterIndex = this.writerIndex();
733 } catch (IndexOutOfBoundsException e) {
734
735 }
736
737 setComponents(list);
738
739
740 localMarkedReaderIndex = Math.max(localMarkedReaderIndex - localReaderIndex, 0);
741 localMarkedWriterIndex = Math.max(localMarkedWriterIndex - localReaderIndex, 0);
742 setIndex(localMarkedReaderIndex, localMarkedWriterIndex);
743 markReaderIndex();
744 markWriterIndex();
745
746 localWriterIndex = Math.max(localWriterIndex - localReaderIndex, 0);
747 setIndex(0, localWriterIndex);
748 }
749
750 @Override
751 public String toString() {
752 String result = super.toString();
753 result = result.substring(0, result.length() - 1);
754 return result + ", components=" + components.length + ")";
755 }
756 }