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