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