View Javadoc
1   /*
2    * Copyright 2012 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.PlatformDependent;
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.ClosedChannelException;
26  import java.nio.channels.FileChannel;
27  import java.nio.channels.GatheringByteChannel;
28  import java.nio.channels.ScatteringByteChannel;
29  
30  /**
31   * A NIO {@link ByteBuffer} based buffer. It is recommended to use
32   * {@link UnpooledByteBufAllocator#directBuffer(int, int)}, {@link Unpooled#directBuffer(int)} and
33   * {@link Unpooled#wrappedBuffer(ByteBuffer)} instead of calling the constructor explicitly.
34   */
35  public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
36  
37      private final ByteBufAllocator alloc;
38  
39      private ByteBuffer buffer;
40      private ByteBuffer tmpNioBuf;
41      private int capacity;
42      private boolean doNotFree;
43  
44      /**
45       * Creates a new direct buffer.
46       *
47       * @param initialCapacity the initial capacity of the underlying direct buffer
48       * @param maxCapacity     the maximum capacity of the underlying direct buffer
49       */
50      public UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
51          super(maxCapacity);
52          if (alloc == null) {
53              throw new NullPointerException("alloc");
54          }
55          if (initialCapacity < 0) {
56              throw new IllegalArgumentException("initialCapacity: " + initialCapacity);
57          }
58          if (maxCapacity < 0) {
59              throw new IllegalArgumentException("maxCapacity: " + maxCapacity);
60          }
61          if (initialCapacity > maxCapacity) {
62              throw new IllegalArgumentException(String.format(
63                      "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
64          }
65  
66          this.alloc = alloc;
67          setByteBuffer(allocateDirect(initialCapacity));
68      }
69  
70      /**
71       * Creates a new direct buffer by wrapping the specified initial buffer.
72       *
73       * @param maxCapacity the maximum capacity of the underlying direct buffer
74       */
75      protected UnpooledDirectByteBuf(ByteBufAllocator alloc, ByteBuffer initialBuffer, int maxCapacity) {
76          super(maxCapacity);
77          if (alloc == null) {
78              throw new NullPointerException("alloc");
79          }
80          if (initialBuffer == null) {
81              throw new NullPointerException("initialBuffer");
82          }
83          if (!initialBuffer.isDirect()) {
84              throw new IllegalArgumentException("initialBuffer is not a direct buffer.");
85          }
86          if (initialBuffer.isReadOnly()) {
87              throw new IllegalArgumentException("initialBuffer is a read-only buffer.");
88          }
89  
90          int initialCapacity = initialBuffer.remaining();
91          if (initialCapacity > maxCapacity) {
92              throw new IllegalArgumentException(String.format(
93                      "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
94          }
95  
96          this.alloc = alloc;
97          doNotFree = true;
98          setByteBuffer(initialBuffer.slice().order(ByteOrder.BIG_ENDIAN));
99          writerIndex(initialCapacity);
100     }
101 
102     /**
103      * Allocate a new direct {@link ByteBuffer} with the given initialCapacity.
104      */
105     protected ByteBuffer allocateDirect(int initialCapacity) {
106         return ByteBuffer.allocateDirect(initialCapacity);
107     }
108 
109     /**
110      * Free a direct {@link ByteBuffer}
111      */
112     protected void freeDirect(ByteBuffer buffer) {
113         PlatformDependent.freeDirectBuffer(buffer);
114     }
115 
116     private void setByteBuffer(ByteBuffer buffer) {
117         ByteBuffer oldBuffer = this.buffer;
118         if (oldBuffer != null) {
119             if (doNotFree) {
120                 doNotFree = false;
121             } else {
122                 freeDirect(oldBuffer);
123             }
124         }
125 
126         this.buffer = buffer;
127         tmpNioBuf = null;
128         capacity = buffer.remaining();
129     }
130 
131     @Override
132     public boolean isDirect() {
133         return true;
134     }
135 
136     @Override
137     public int capacity() {
138         return capacity;
139     }
140 
141     @Override
142     public ByteBuf capacity(int newCapacity) {
143         checkNewCapacity(newCapacity);
144 
145         int readerIndex = readerIndex();
146         int writerIndex = writerIndex();
147 
148         int oldCapacity = capacity;
149         if (newCapacity > oldCapacity) {
150             ByteBuffer oldBuffer = buffer;
151             ByteBuffer newBuffer = allocateDirect(newCapacity);
152             oldBuffer.position(0).limit(oldBuffer.capacity());
153             newBuffer.position(0).limit(oldBuffer.capacity());
154             newBuffer.put(oldBuffer);
155             newBuffer.clear();
156             setByteBuffer(newBuffer);
157         } else if (newCapacity < oldCapacity) {
158             ByteBuffer oldBuffer = buffer;
159             ByteBuffer newBuffer = allocateDirect(newCapacity);
160             if (readerIndex < newCapacity) {
161                 if (writerIndex > newCapacity) {
162                     writerIndex(writerIndex = newCapacity);
163                 }
164                 oldBuffer.position(readerIndex).limit(writerIndex);
165                 newBuffer.position(readerIndex).limit(writerIndex);
166                 newBuffer.put(oldBuffer);
167                 newBuffer.clear();
168             } else {
169                 setIndex(newCapacity, newCapacity);
170             }
171             setByteBuffer(newBuffer);
172         }
173         return this;
174     }
175 
176     @Override
177     public ByteBufAllocator alloc() {
178         return alloc;
179     }
180 
181     @Override
182     public ByteOrder order() {
183         return ByteOrder.BIG_ENDIAN;
184     }
185 
186     @Override
187     public boolean hasArray() {
188         return false;
189     }
190 
191     @Override
192     public byte[] array() {
193         throw new UnsupportedOperationException("direct buffer");
194     }
195 
196     @Override
197     public int arrayOffset() {
198         throw new UnsupportedOperationException("direct buffer");
199     }
200 
201     @Override
202     public boolean hasMemoryAddress() {
203         return false;
204     }
205 
206     @Override
207     public long memoryAddress() {
208         throw new UnsupportedOperationException();
209     }
210 
211     @Override
212     public byte getByte(int index) {
213         ensureAccessible();
214         return _getByte(index);
215     }
216 
217     @Override
218     protected byte _getByte(int index) {
219         return buffer.get(index);
220     }
221 
222     @Override
223     public short getShort(int index) {
224         ensureAccessible();
225         return _getShort(index);
226     }
227 
228     @Override
229     protected short _getShort(int index) {
230         return buffer.getShort(index);
231     }
232 
233     @Override
234     protected short _getShortLE(int index) {
235         return ByteBufUtil.swapShort(buffer.getShort(index));
236     }
237 
238     @Override
239     public int getUnsignedMedium(int index) {
240         ensureAccessible();
241         return _getUnsignedMedium(index);
242     }
243 
244     @Override
245     protected int _getUnsignedMedium(int index) {
246         return (getByte(index) & 0xff)     << 16 |
247                (getByte(index + 1) & 0xff) << 8  |
248                getByte(index + 2) & 0xff;
249     }
250 
251     @Override
252     protected int _getUnsignedMediumLE(int index) {
253         return getByte(index) & 0xff             |
254                (getByte(index + 1) & 0xff) << 8  |
255                (getByte(index + 2) & 0xff) << 16;
256     }
257 
258     @Override
259     public int getInt(int index) {
260         ensureAccessible();
261         return _getInt(index);
262     }
263 
264     @Override
265     protected int _getInt(int index) {
266         return buffer.getInt(index);
267     }
268 
269     @Override
270     protected int _getIntLE(int index) {
271         return ByteBufUtil.swapInt(buffer.getInt(index));
272     }
273 
274     @Override
275     public long getLong(int index) {
276         ensureAccessible();
277         return _getLong(index);
278     }
279 
280     @Override
281     protected long _getLong(int index) {
282         return buffer.getLong(index);
283     }
284 
285     @Override
286     protected long _getLongLE(int index) {
287         return ByteBufUtil.swapLong(buffer.getLong(index));
288     }
289 
290     @Override
291     public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
292         checkDstIndex(index, length, dstIndex, dst.capacity());
293         if (dst.hasArray()) {
294             getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length);
295         } else if (dst.nioBufferCount() > 0) {
296             for (ByteBuffer bb: dst.nioBuffers(dstIndex, length)) {
297                 int bbLen = bb.remaining();
298                 getBytes(index, bb);
299                 index += bbLen;
300             }
301         } else {
302             dst.setBytes(dstIndex, this, index, length);
303         }
304         return this;
305     }
306 
307     @Override
308     public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
309         getBytes(index, dst, dstIndex, length, false);
310         return this;
311     }
312 
313     private void getBytes(int index, byte[] dst, int dstIndex, int length, boolean internal) {
314         checkDstIndex(index, length, dstIndex, dst.length);
315 
316         ByteBuffer tmpBuf;
317         if (internal) {
318             tmpBuf = internalNioBuffer();
319         } else {
320             tmpBuf = buffer.duplicate();
321         }
322         tmpBuf.clear().position(index).limit(index + length);
323         tmpBuf.get(dst, dstIndex, length);
324     }
325 
326     @Override
327     public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
328         checkReadableBytes(length);
329         getBytes(readerIndex, dst, dstIndex, length, true);
330         readerIndex += length;
331         return this;
332     }
333 
334     @Override
335     public ByteBuf getBytes(int index, ByteBuffer dst) {
336         getBytes(index, dst, false);
337         return this;
338     }
339 
340     private void getBytes(int index, ByteBuffer dst, boolean internal) {
341         checkIndex(index, dst.remaining());
342 
343         ByteBuffer tmpBuf;
344         if (internal) {
345             tmpBuf = internalNioBuffer();
346         } else {
347             tmpBuf = buffer.duplicate();
348         }
349         tmpBuf.clear().position(index).limit(index + dst.remaining());
350         dst.put(tmpBuf);
351     }
352 
353     @Override
354     public ByteBuf readBytes(ByteBuffer dst) {
355         int length = dst.remaining();
356         checkReadableBytes(length);
357         getBytes(readerIndex, dst, true);
358         readerIndex += length;
359         return this;
360     }
361 
362     @Override
363     public ByteBuf setByte(int index, int value) {
364         ensureAccessible();
365         _setByte(index, value);
366         return this;
367     }
368 
369     @Override
370     protected void _setByte(int index, int value) {
371         buffer.put(index, (byte) value);
372     }
373 
374     @Override
375     public ByteBuf setShort(int index, int value) {
376         ensureAccessible();
377         _setShort(index, value);
378         return this;
379     }
380 
381     @Override
382     protected void _setShort(int index, int value) {
383         buffer.putShort(index, (short) value);
384     }
385 
386     @Override
387     protected void _setShortLE(int index, int value) {
388         buffer.putShort(index, ByteBufUtil.swapShort((short) value));
389     }
390 
391     @Override
392     public ByteBuf setMedium(int index, int value) {
393         ensureAccessible();
394         _setMedium(index, value);
395         return this;
396     }
397 
398     @Override
399     protected void _setMedium(int index, int value) {
400         setByte(index, (byte) (value >>> 16));
401         setByte(index + 1, (byte) (value >>> 8));
402         setByte(index + 2, (byte) value);
403     }
404 
405     @Override
406     protected void _setMediumLE(int index, int value) {
407         setByte(index, (byte) value);
408         setByte(index + 1, (byte) (value >>> 8));
409         setByte(index + 2, (byte) (value >>> 16));
410     }
411 
412     @Override
413     public ByteBuf setInt(int index, int value) {
414         ensureAccessible();
415         _setInt(index, value);
416         return this;
417     }
418 
419     @Override
420     protected void _setInt(int index, int value) {
421         buffer.putInt(index, value);
422     }
423 
424     @Override
425     protected void _setIntLE(int index, int value) {
426         buffer.putInt(index, ByteBufUtil.swapInt(value));
427     }
428 
429     @Override
430     public ByteBuf setLong(int index, long value) {
431         ensureAccessible();
432         _setLong(index, value);
433         return this;
434     }
435 
436     @Override
437     protected void _setLong(int index, long value) {
438         buffer.putLong(index, value);
439     }
440 
441     @Override
442     protected void _setLongLE(int index, long value) {
443         buffer.putLong(index, ByteBufUtil.swapLong(value));
444     }
445 
446     @Override
447     public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
448         checkSrcIndex(index, length, srcIndex, src.capacity());
449         if (src.nioBufferCount() > 0) {
450             for (ByteBuffer bb: src.nioBuffers(srcIndex, length)) {
451                 int bbLen = bb.remaining();
452                 setBytes(index, bb);
453                 index += bbLen;
454             }
455         } else {
456             src.getBytes(srcIndex, this, index, length);
457         }
458         return this;
459     }
460 
461     @Override
462     public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
463         checkSrcIndex(index, length, srcIndex, src.length);
464         ByteBuffer tmpBuf = internalNioBuffer();
465         tmpBuf.clear().position(index).limit(index + length);
466         tmpBuf.put(src, srcIndex, length);
467         return this;
468     }
469 
470     @Override
471     public ByteBuf setBytes(int index, ByteBuffer src) {
472         ensureAccessible();
473         ByteBuffer tmpBuf = internalNioBuffer();
474         if (src == tmpBuf) {
475             src = src.duplicate();
476         }
477 
478         tmpBuf.clear().position(index).limit(index + src.remaining());
479         tmpBuf.put(src);
480         return this;
481     }
482 
483     @Override
484     public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
485         getBytes(index, out, length, false);
486         return this;
487     }
488 
489     private void getBytes(int index, OutputStream out, int length, boolean internal) throws IOException {
490         ensureAccessible();
491         if (length == 0) {
492             return;
493         }
494         ByteBufUtil.readBytes(alloc(), internal ? internalNioBuffer() : buffer.duplicate(), index, length, out);
495     }
496 
497     @Override
498     public ByteBuf readBytes(OutputStream out, int length) throws IOException {
499         checkReadableBytes(length);
500         getBytes(readerIndex, out, length, true);
501         readerIndex += length;
502         return this;
503     }
504 
505     @Override
506     public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
507         return getBytes(index, out, length, false);
508     }
509 
510     private int getBytes(int index, GatheringByteChannel out, int length, boolean internal) throws IOException {
511         ensureAccessible();
512         if (length == 0) {
513             return 0;
514         }
515 
516         ByteBuffer tmpBuf;
517         if (internal) {
518             tmpBuf = internalNioBuffer();
519         } else {
520             tmpBuf = buffer.duplicate();
521         }
522         tmpBuf.clear().position(index).limit(index + length);
523         return out.write(tmpBuf);
524     }
525 
526     @Override
527     public int getBytes(int index, FileChannel out, long position, int length) throws IOException {
528         return getBytes(index, out, position, length, false);
529     }
530 
531     private int getBytes(int index, FileChannel out, long position, int length, boolean internal) throws IOException {
532         ensureAccessible();
533         if (length == 0) {
534             return 0;
535         }
536 
537         ByteBuffer tmpBuf = internal ? internalNioBuffer() : buffer.duplicate();
538         tmpBuf.clear().position(index).limit(index + length);
539         return out.write(tmpBuf, position);
540     }
541 
542     @Override
543     public int readBytes(GatheringByteChannel out, int length) throws IOException {
544         checkReadableBytes(length);
545         int readBytes = getBytes(readerIndex, out, length, true);
546         readerIndex += readBytes;
547         return readBytes;
548     }
549 
550     @Override
551     public int readBytes(FileChannel out, long position, int length) throws IOException {
552         checkReadableBytes(length);
553         int readBytes = getBytes(readerIndex, out, position, length, true);
554         readerIndex += readBytes;
555         return readBytes;
556     }
557 
558     @Override
559     public int setBytes(int index, InputStream in, int length) throws IOException {
560         ensureAccessible();
561         if (buffer.hasArray()) {
562             return in.read(buffer.array(), buffer.arrayOffset() + index, length);
563         } else {
564             byte[] tmp = ByteBufUtil.threadLocalTempArray(length);
565             int readBytes = in.read(tmp, 0, length);
566             if (readBytes <= 0) {
567                 return readBytes;
568             }
569             ByteBuffer tmpBuf = internalNioBuffer();
570             tmpBuf.clear().position(index);
571             tmpBuf.put(tmp, 0, readBytes);
572             return readBytes;
573         }
574     }
575 
576     @Override
577     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
578         ensureAccessible();
579         ByteBuffer tmpBuf = internalNioBuffer();
580         tmpBuf.clear().position(index).limit(index + length);
581         try {
582             return in.read(tmpNioBuf);
583         } catch (ClosedChannelException ignored) {
584             return -1;
585         }
586     }
587 
588     @Override
589     public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
590         ensureAccessible();
591         ByteBuffer tmpBuf = internalNioBuffer();
592         tmpBuf.clear().position(index).limit(index + length);
593         try {
594             return in.read(tmpNioBuf, position);
595         } catch (ClosedChannelException ignored) {
596             return -1;
597         }
598     }
599 
600     @Override
601     public int nioBufferCount() {
602         return 1;
603     }
604 
605     @Override
606     public ByteBuffer[] nioBuffers(int index, int length) {
607         return new ByteBuffer[] { nioBuffer(index, length) };
608     }
609 
610     @Override
611     public ByteBuf copy(int index, int length) {
612         ensureAccessible();
613         ByteBuffer src;
614         try {
615             src = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
616         } catch (IllegalArgumentException ignored) {
617             throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length));
618         }
619 
620         return alloc().directBuffer(length, maxCapacity()).writeBytes(src);
621     }
622 
623     @Override
624     public ByteBuffer internalNioBuffer(int index, int length) {
625         checkIndex(index, length);
626         return (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
627     }
628 
629     private ByteBuffer internalNioBuffer() {
630         ByteBuffer tmpNioBuf = this.tmpNioBuf;
631         if (tmpNioBuf == null) {
632             this.tmpNioBuf = tmpNioBuf = buffer.duplicate();
633         }
634         return tmpNioBuf;
635     }
636 
637     @Override
638     public ByteBuffer nioBuffer(int index, int length) {
639         checkIndex(index, length);
640         return ((ByteBuffer) buffer.duplicate().position(index).limit(index + length)).slice();
641     }
642 
643     @Override
644     protected void deallocate() {
645         ByteBuffer buffer = this.buffer;
646         if (buffer == null) {
647             return;
648         }
649 
650         this.buffer = null;
651 
652         if (!doNotFree) {
653             freeDirect(buffer);
654         }
655     }
656 
657     @Override
658     public ByteBuf unwrap() {
659         return null;
660     }
661 }