View Javadoc
1   /*
2    * Copyright 2013 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.buffer;
17  
18  import io.netty.util.internal.EmptyArrays;
19  import io.netty.util.internal.RecyclableArrayList;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.OutputStream;
24  import java.nio.ByteBuffer;
25  import java.nio.ByteOrder;
26  import java.nio.ReadOnlyBufferException;
27  import java.nio.channels.FileChannel;
28  import java.nio.channels.GatheringByteChannel;
29  import java.nio.channels.ScatteringByteChannel;
30  import java.util.Collections;
31  
32  /**
33   * {@link ByteBuf} implementation which allows to wrap an array of {@link ByteBuf} in a read-only mode.
34   * This is useful to write an array of {@link ByteBuf}s.
35   */
36  final class FixedCompositeByteBuf extends AbstractReferenceCountedByteBuf {
37      private static final ByteBuf[] EMPTY = { Unpooled.EMPTY_BUFFER };
38      private final int nioBufferCount;
39      private final int capacity;
40      private final ByteBufAllocator allocator;
41      private final ByteOrder order;
42      private final ByteBuf[] buffers;
43      private final boolean direct;
44  
45      FixedCompositeByteBuf(ByteBufAllocator allocator, ByteBuf... buffers) {
46          super(AbstractByteBufAllocator.DEFAULT_MAX_CAPACITY);
47          if (buffers.length == 0) {
48              this.buffers = EMPTY;
49              order = ByteOrder.BIG_ENDIAN;
50              nioBufferCount = 1;
51              capacity = 0;
52              direct = false;
53          } else {
54              ByteBuf b = buffers[0];
55              this.buffers = buffers;
56              boolean direct = true;
57              int nioBufferCount = b.nioBufferCount();
58              int capacity = b.readableBytes();
59              order = b.order();
60              for (int i = 1; i < buffers.length; i++) {
61                  b = buffers[i];
62                  if (buffers[i].order() != order) {
63                      throw new IllegalArgumentException("All ByteBufs need to have same ByteOrder");
64                  }
65                  nioBufferCount += b.nioBufferCount();
66                  capacity += b.readableBytes();
67                  if (!b.isDirect()) {
68                      direct = false;
69                  }
70              }
71              this.nioBufferCount = nioBufferCount;
72              this.capacity = capacity;
73              this.direct = direct;
74          }
75          setIndex(0, capacity());
76          this.allocator = allocator;
77      }
78  
79      @Override
80      public boolean isWritable() {
81          return false;
82      }
83  
84      @Override
85      public boolean isWritable(int size) {
86          return false;
87      }
88  
89      @Override
90      public ByteBuf discardReadBytes() {
91          throw new ReadOnlyBufferException();
92      }
93  
94      @Override
95      public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
96          throw new ReadOnlyBufferException();
97      }
98  
99      @Override
100     public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
101         throw new ReadOnlyBufferException();
102     }
103 
104     @Override
105     public ByteBuf setBytes(int index, ByteBuffer src) {
106         throw new ReadOnlyBufferException();
107     }
108 
109     @Override
110     public ByteBuf setByte(int index, int value) {
111         throw new ReadOnlyBufferException();
112     }
113 
114     @Override
115     protected void _setByte(int index, int value) {
116         throw new ReadOnlyBufferException();
117     }
118 
119     @Override
120     public ByteBuf setShort(int index, int value) {
121         throw new ReadOnlyBufferException();
122     }
123 
124     @Override
125     protected void _setShort(int index, int value) {
126         throw new ReadOnlyBufferException();
127     }
128 
129     @Override
130     protected void _setShortLE(int index, int value) {
131         throw new ReadOnlyBufferException();
132     }
133 
134     @Override
135     public ByteBuf setMedium(int index, int value) {
136         throw new ReadOnlyBufferException();
137     }
138 
139     @Override
140     protected void _setMedium(int index, int value) {
141         throw new ReadOnlyBufferException();
142     }
143 
144     @Override
145     protected void _setMediumLE(int index, int value) {
146         throw new ReadOnlyBufferException();
147     }
148 
149     @Override
150     public ByteBuf setInt(int index, int value) {
151         throw new ReadOnlyBufferException();
152     }
153 
154     @Override
155     protected void _setInt(int index, int value) {
156         throw new ReadOnlyBufferException();
157     }
158 
159     @Override
160     protected void _setIntLE(int index, int value) {
161         throw new ReadOnlyBufferException();
162     }
163 
164     @Override
165     public ByteBuf setLong(int index, long value) {
166         throw new ReadOnlyBufferException();
167     }
168 
169     @Override
170     protected void _setLong(int index, long value) {
171         throw new ReadOnlyBufferException();
172     }
173 
174     @Override
175     protected void _setLongLE(int index, long value) {
176         throw new ReadOnlyBufferException();
177     }
178 
179     @Override
180     public int setBytes(int index, InputStream in, int length) {
181         throw new ReadOnlyBufferException();
182     }
183 
184     @Override
185     public int setBytes(int index, ScatteringByteChannel in, int length) {
186         throw new ReadOnlyBufferException();
187     }
188 
189     @Override
190     public int setBytes(int index, FileChannel in, long position, int length) {
191         throw new ReadOnlyBufferException();
192     }
193 
194     @Override
195     public int capacity() {
196         return capacity;
197     }
198 
199     @Override
200     public int maxCapacity() {
201         return capacity;
202     }
203 
204     @Override
205     public ByteBuf capacity(int newCapacity) {
206         throw new ReadOnlyBufferException();
207     }
208 
209     @Override
210     public ByteBufAllocator alloc() {
211         return allocator;
212     }
213 
214     @Override
215     public ByteOrder order() {
216         return order;
217     }
218 
219     @Override
220     public ByteBuf unwrap() {
221         return null;
222     }
223 
224     @Override
225     public boolean isDirect() {
226         return direct;
227     }
228 
229     private Component findComponent(int index) {
230         int readable = 0;
231         for (int i = 0 ; i < buffers.length; i++) {
232             Component comp = null;
233             ByteBuf b = buffers[i];
234             if (b instanceof Component) {
235                 comp = (Component) b;
236                 b = comp.buf;
237             }
238             readable += b.readableBytes();
239             if (index < readable) {
240                 if (comp == null) {
241                     // Create a new component and store it in the array so it not create a new object
242                     // on the next access.
243                     comp = new Component(i, readable - b.readableBytes(), b);
244                     buffers[i] = comp;
245                 }
246                 return comp;
247             }
248         }
249         throw new IllegalStateException();
250     }
251 
252     /**
253      * Return the {@link ByteBuf} stored at the given index of the array.
254      */
255     private ByteBuf buffer(int i) {
256         ByteBuf b = buffers[i];
257         return b instanceof Component ? ((Component) b).buf : b;
258     }
259 
260     @Override
261     public byte getByte(int index) {
262         return _getByte(index);
263     }
264 
265     @Override
266     protected byte _getByte(int index) {
267         Component c = findComponent(index);
268         return c.buf.getByte(index - c.offset);
269     }
270 
271     @Override
272     protected short _getShort(int index) {
273         Component c = findComponent(index);
274         if (index + 2 <= c.endOffset) {
275             return c.buf.getShort(index - c.offset);
276         } else if (order() == ByteOrder.BIG_ENDIAN) {
277             return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff);
278         } else {
279             return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8);
280         }
281     }
282 
283     @Override
284     protected short _getShortLE(int index) {
285         Component c = findComponent(index);
286         if (index + 2 <= c.endOffset) {
287             return c.buf.getShortLE(index - c.offset);
288         } else if (order() == ByteOrder.BIG_ENDIAN) {
289             return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8);
290         } else {
291             return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff);
292         }
293     }
294 
295     @Override
296     protected int _getUnsignedMedium(int index) {
297         Component c = findComponent(index);
298         if (index + 3 <= c.endOffset) {
299             return c.buf.getUnsignedMedium(index - c.offset);
300         } else if (order() == ByteOrder.BIG_ENDIAN) {
301             return (_getShort(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff;
302         } else {
303             return _getShort(index) & 0xFFFF | (_getByte(index + 2) & 0xFF) << 16;
304         }
305     }
306 
307     @Override
308     protected int _getUnsignedMediumLE(int index) {
309         Component c = findComponent(index);
310         if (index + 3 <= c.endOffset) {
311             return c.buf.getUnsignedMediumLE(index - c.offset);
312         } else if (order() == ByteOrder.BIG_ENDIAN) {
313             return _getShortLE(index) & 0xffff | (_getByte(index + 2) & 0xff) << 16;
314         } else {
315             return (_getShortLE(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff;
316         }
317     }
318 
319     @Override
320     protected int _getInt(int index) {
321         Component c = findComponent(index);
322         if (index + 4 <= c.endOffset) {
323             return c.buf.getInt(index - c.offset);
324         } else if (order() == ByteOrder.BIG_ENDIAN) {
325             return (_getShort(index) & 0xffff) << 16 | _getShort(index + 2) & 0xffff;
326         } else {
327             return _getShort(index) & 0xFFFF | (_getShort(index + 2) & 0xFFFF) << 16;
328         }
329     }
330 
331     @Override
332     protected int _getIntLE(int index) {
333         Component c = findComponent(index);
334         if (index + 4 <= c.endOffset) {
335             return c.buf.getIntLE(index - c.offset);
336         } else if (order() == ByteOrder.BIG_ENDIAN) {
337             return _getShortLE(index) & 0xFFFF | (_getShortLE(index + 2) & 0xFFFF) << 16;
338         } else {
339             return (_getShortLE(index) & 0xffff) << 16 | _getShortLE(index + 2) & 0xffff;
340         }
341     }
342 
343     @Override
344     protected long _getLong(int index) {
345         Component c = findComponent(index);
346         if (index + 8 <= c.endOffset) {
347             return c.buf.getLong(index - c.offset);
348         } else if (order() == ByteOrder.BIG_ENDIAN) {
349             return (_getInt(index) & 0xffffffffL) << 32 | _getInt(index + 4) & 0xffffffffL;
350         } else {
351             return _getInt(index) & 0xFFFFFFFFL | (_getInt(index + 4) & 0xFFFFFFFFL) << 32;
352         }
353     }
354 
355     @Override
356     protected long _getLongLE(int index) {
357         Component c = findComponent(index);
358         if (index + 8 <= c.endOffset) {
359             return c.buf.getLongLE(index - c.offset);
360         } else if (order() == ByteOrder.BIG_ENDIAN) {
361             return _getIntLE(index) & 0xffffffffL | (_getIntLE(index + 4) & 0xffffffffL) << 32;
362         } else {
363             return (_getIntLE(index) & 0xffffffffL) << 32 | _getIntLE(index + 4) & 0xffffffffL;
364         }
365     }
366 
367     @Override
368     public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
369         checkDstIndex(index, length, dstIndex, dst.length);
370         if (length == 0) {
371             return this;
372         }
373 
374         Component c = findComponent(index);
375         int i = c.index;
376         int adjustment = c.offset;
377         ByteBuf s = c.buf;
378         for (;;) {
379             int localLength = Math.min(length, s.readableBytes() - (index - adjustment));
380             s.getBytes(index - adjustment, dst, dstIndex, localLength);
381             index += localLength;
382             dstIndex += localLength;
383             length -= localLength;
384             adjustment += s.readableBytes();
385             if (length <= 0) {
386                 break;
387             }
388             s = buffer(++i);
389         }
390         return this;
391     }
392 
393     @Override
394     public ByteBuf getBytes(int index, ByteBuffer dst) {
395         int limit = dst.limit();
396         int length = dst.remaining();
397 
398         checkIndex(index, length);
399         if (length == 0) {
400             return this;
401         }
402 
403         try {
404             Component c = findComponent(index);
405             int i = c.index;
406             int adjustment = c.offset;
407             ByteBuf s = c.buf;
408             for (;;) {
409                 int localLength = Math.min(length, s.readableBytes() - (index - adjustment));
410                 dst.limit(dst.position() + localLength);
411                 s.getBytes(index - adjustment, dst);
412                 index += localLength;
413                 length -= localLength;
414                 adjustment += s.readableBytes();
415                 if (length <= 0) {
416                     break;
417                 }
418                 s = buffer(++i);
419             }
420         } finally {
421             dst.limit(limit);
422         }
423         return this;
424     }
425 
426     @Override
427     public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
428         checkDstIndex(index, length, dstIndex, dst.capacity());
429         if (length == 0) {
430             return this;
431         }
432 
433         Component c = findComponent(index);
434         int i = c.index;
435         int adjustment = c.offset;
436         ByteBuf s = c.buf;
437         for (;;) {
438             int localLength = Math.min(length, s.readableBytes() - (index - adjustment));
439             s.getBytes(index - adjustment, dst, dstIndex, localLength);
440             index += localLength;
441             dstIndex += localLength;
442             length -= localLength;
443             adjustment += s.readableBytes();
444             if (length <= 0) {
445                 break;
446             }
447             s = buffer(++i);
448         }
449         return this;
450     }
451 
452     @Override
453     public int getBytes(int index, GatheringByteChannel out, int length)
454             throws IOException {
455         int count = nioBufferCount();
456         if (count == 1) {
457             return out.write(internalNioBuffer(index, length));
458         } else {
459             long writtenBytes = out.write(nioBuffers(index, length));
460             if (writtenBytes > Integer.MAX_VALUE) {
461                 return Integer.MAX_VALUE;
462             } else {
463                 return (int) writtenBytes;
464             }
465         }
466     }
467 
468     @Override
469     public int getBytes(int index, FileChannel out, long position, int length)
470             throws IOException {
471         int count = nioBufferCount();
472         if (count == 1) {
473             return out.write(internalNioBuffer(index, length), position);
474         } else {
475             long writtenBytes = 0;
476             for (ByteBuffer buf : nioBuffers(index, length)) {
477                 writtenBytes += out.write(buf, position + writtenBytes);
478             }
479             if (writtenBytes > Integer.MAX_VALUE) {
480                 return Integer.MAX_VALUE;
481             } else {
482                 return (int) writtenBytes;
483             }
484         }
485     }
486 
487     @Override
488     public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
489         checkIndex(index, length);
490         if (length == 0) {
491             return this;
492         }
493 
494         Component c = findComponent(index);
495         int i = c.index;
496         int adjustment = c.offset;
497         ByteBuf s = c.buf;
498         for (;;) {
499             int localLength = Math.min(length, s.readableBytes() - (index - adjustment));
500             s.getBytes(index - adjustment, out, localLength);
501             index += localLength;
502             length -= localLength;
503             adjustment += s.readableBytes();
504             if (length <= 0) {
505                 break;
506             }
507             s = buffer(++i);
508         }
509         return this;
510     }
511 
512     @Override
513     public ByteBuf copy(int index, int length) {
514         checkIndex(index, length);
515         boolean release = true;
516         ByteBuf buf = alloc().buffer(length);
517         try {
518             buf.writeBytes(this, index, length);
519             release = false;
520             return buf;
521         } finally {
522             if (release) {
523                 buf.release();
524             }
525         }
526     }
527 
528     @Override
529     public int nioBufferCount() {
530         return nioBufferCount;
531     }
532 
533     @Override
534     public ByteBuffer nioBuffer(int index, int length) {
535         checkIndex(index, length);
536         if (buffers.length == 1) {
537             ByteBuf buf = buffer(0);
538             if (buf.nioBufferCount() == 1) {
539                 return buf.nioBuffer(index, length);
540             }
541         }
542         ByteBuffer merged = ByteBuffer.allocate(length).order(order());
543         ByteBuffer[] buffers = nioBuffers(index, length);
544 
545         //noinspection ForLoopReplaceableByForEach
546         for (int i = 0; i < buffers.length; i++) {
547             merged.put(buffers[i]);
548         }
549 
550         merged.flip();
551         return merged;
552     }
553 
554     @Override
555     public ByteBuffer internalNioBuffer(int index, int length) {
556         if (buffers.length == 1) {
557             return buffer(0).internalNioBuffer(index, length);
558         }
559         throw new UnsupportedOperationException();
560     }
561 
562     @Override
563     public ByteBuffer[] nioBuffers(int index, int length) {
564         checkIndex(index, length);
565         if (length == 0) {
566             return EmptyArrays.EMPTY_BYTE_BUFFERS;
567         }
568 
569         RecyclableArrayList array = RecyclableArrayList.newInstance(buffers.length);
570         try {
571             Component c = findComponent(index);
572             int i = c.index;
573             int adjustment = c.offset;
574             ByteBuf s = c.buf;
575             for (;;) {
576                 int localLength = Math.min(length, s.readableBytes() - (index - adjustment));
577                 switch (s.nioBufferCount()) {
578                     case 0:
579                         throw new UnsupportedOperationException();
580                     case 1:
581                         array.add(s.nioBuffer(index - adjustment, localLength));
582                         break;
583                     default:
584                         Collections.addAll(array, s.nioBuffers(index - adjustment, localLength));
585                 }
586 
587                 index += localLength;
588                 length -= localLength;
589                 adjustment += s.readableBytes();
590                 if (length <= 0) {
591                     break;
592                 }
593                 s = buffer(++i);
594             }
595 
596             return array.toArray(new ByteBuffer[0]);
597         } finally {
598             array.recycle();
599         }
600     }
601 
602     @Override
603     public boolean hasArray() {
604         switch (buffers.length) {
605             case 0:
606                 return true;
607             case 1:
608                 return buffer(0).hasArray();
609             default:
610                 return false;
611         }
612     }
613 
614     @Override
615     public byte[] array() {
616         switch (buffers.length) {
617             case 0:
618                 return EmptyArrays.EMPTY_BYTES;
619             case 1:
620                 return buffer(0).array();
621             default:
622                 throw new UnsupportedOperationException();
623         }
624     }
625 
626     @Override
627     public int arrayOffset() {
628         switch (buffers.length) {
629             case 0:
630                 return 0;
631             case 1:
632                 return buffer(0).arrayOffset();
633             default:
634                 throw new UnsupportedOperationException();
635         }
636     }
637 
638     @Override
639     public boolean hasMemoryAddress() {
640         switch (buffers.length) {
641             case 0:
642                 return Unpooled.EMPTY_BUFFER.hasMemoryAddress();
643             case 1:
644                 return buffer(0).hasMemoryAddress();
645             default:
646                 return false;
647         }
648     }
649 
650     @Override
651     public long memoryAddress() {
652         switch (buffers.length) {
653             case 0:
654                 return Unpooled.EMPTY_BUFFER.memoryAddress();
655             case 1:
656                 return buffer(0).memoryAddress();
657             default:
658                 throw new UnsupportedOperationException();
659         }
660     }
661 
662     @Override
663     protected void deallocate() {
664         for (int i = 0; i < buffers.length; i++) {
665              buffer(i).release();
666         }
667     }
668 
669     @Override
670     public String toString() {
671         String result = super.toString();
672         result = result.substring(0, result.length() - 1);
673         return result + ", components=" + buffers.length + ')';
674     }
675 
676     private static final class Component extends WrappedByteBuf {
677         private final int index;
678         private final int offset;
679         private final int endOffset;
680 
681         Component(int index, int offset, ByteBuf buf) {
682             super(buf);
683             this.index = index;
684             this.offset = offset;
685             endOffset = offset + buf.readableBytes();
686         }
687     }
688 }