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