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