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