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