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