View Javadoc
1   /*
2    * Copyright 2013 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.buffer;
17  
18  import io.netty.util.internal.StringUtil;
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.ReadOnlyBufferException;
26  import java.nio.channels.FileChannel;
27  import java.nio.channels.GatheringByteChannel;
28  import java.nio.channels.ScatteringByteChannel;
29  
30  
31  /**
32   * Read-only ByteBuf which wraps a read-only ByteBuffer.
33   */
34  class ReadOnlyByteBufferBuf extends AbstractReferenceCountedByteBuf {
35  
36      protected final ByteBuffer buffer;
37      private final ByteBufAllocator allocator;
38      private ByteBuffer tmpNioBuf;
39  
40      ReadOnlyByteBufferBuf(ByteBufAllocator allocator, ByteBuffer buffer) {
41          super(buffer.remaining());
42          if (!buffer.isReadOnly()) {
43              throw new IllegalArgumentException("must be a readonly buffer: " + StringUtil.simpleClassName(buffer));
44          }
45  
46          this.allocator = allocator;
47          this.buffer = buffer.slice().order(ByteOrder.BIG_ENDIAN);
48          writerIndex(this.buffer.limit());
49      }
50  
51      @Override
52      protected void deallocate() { }
53  
54      @Override
55      public byte getByte(int index) {
56          ensureAccessible();
57          return _getByte(index);
58      }
59  
60      @Override
61      protected byte _getByte(int index) {
62          return buffer.get(index);
63      }
64  
65      @Override
66      public short getShort(int index) {
67          ensureAccessible();
68          return _getShort(index);
69      }
70  
71      @Override
72      protected short _getShort(int index) {
73          return buffer.getShort(index);
74      }
75  
76      @Override
77      public short getShortLE(int index) {
78          ensureAccessible();
79          return _getShortLE(index);
80      }
81  
82      @Override
83      protected short _getShortLE(int index) {
84          return ByteBufUtil.swapShort(buffer.getShort(index));
85      }
86  
87      @Override
88      public int getUnsignedMedium(int index) {
89          ensureAccessible();
90          return _getUnsignedMedium(index);
91      }
92  
93      @Override
94      protected int _getUnsignedMedium(int index) {
95          return (getByte(index) & 0xff)     << 16 |
96                 (getByte(index + 1) & 0xff) << 8  |
97                 getByte(index + 2) & 0xff;
98      }
99  
100     @Override
101     public int getUnsignedMediumLE(int index) {
102         ensureAccessible();
103         return _getUnsignedMediumLE(index);
104     }
105 
106     @Override
107     protected int _getUnsignedMediumLE(int index) {
108         return getByte(index)      & 0xff       |
109                (getByte(index + 1) & 0xff) << 8 |
110                (getByte(index + 2) & 0xff) << 16;
111     }
112 
113     @Override
114     public int getInt(int index) {
115         ensureAccessible();
116         return _getInt(index);
117     }
118 
119     @Override
120     protected int _getInt(int index) {
121         return buffer.getInt(index);
122     }
123 
124     @Override
125     public int getIntLE(int index) {
126         ensureAccessible();
127         return _getIntLE(index);
128     }
129 
130     @Override
131     protected int _getIntLE(int index) {
132         return ByteBufUtil.swapInt(buffer.getInt(index));
133     }
134 
135     @Override
136     public long getLong(int index) {
137         ensureAccessible();
138         return _getLong(index);
139     }
140 
141     @Override
142     protected long _getLong(int index) {
143         return buffer.getLong(index);
144     }
145 
146     @Override
147     public long getLongLE(int index) {
148         ensureAccessible();
149         return _getLongLE(index);
150     }
151 
152     @Override
153     protected long _getLongLE(int index) {
154         return ByteBufUtil.swapLong(buffer.getLong(index));
155     }
156 
157     @Override
158     public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
159         checkDstIndex(index, length, dstIndex, dst.capacity());
160         if (dst.hasArray()) {
161             getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length);
162         } else if (dst.nioBufferCount() > 0) {
163             for (ByteBuffer bb: dst.nioBuffers(dstIndex, length)) {
164                 int bbLen = bb.remaining();
165                 getBytes(index, bb);
166                 index += bbLen;
167             }
168         } else {
169             dst.setBytes(dstIndex, this, index, length);
170         }
171         return this;
172     }
173 
174     @Override
175     public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
176         checkDstIndex(index, length, dstIndex, dst.length);
177 
178         if (dstIndex < 0 || dstIndex > dst.length - length) {
179             throw new IndexOutOfBoundsException(String.format(
180                     "dstIndex: %d, length: %d (expected: range(0, %d))", dstIndex, length, dst.length));
181         }
182 
183         ByteBuffer tmpBuf = internalNioBuffer();
184         tmpBuf.clear().position(index).limit(index + length);
185         tmpBuf.get(dst, dstIndex, length);
186         return this;
187     }
188 
189     @Override
190     public ByteBuf getBytes(int index, ByteBuffer dst) {
191         checkIndex(index);
192         if (dst == null) {
193             throw new NullPointerException("dst");
194         }
195 
196         int bytesToCopy = Math.min(capacity() - index, dst.remaining());
197         ByteBuffer tmpBuf = internalNioBuffer();
198         tmpBuf.clear().position(index).limit(index + bytesToCopy);
199         dst.put(tmpBuf);
200         return this;
201     }
202 
203     @Override
204     public ByteBuf setByte(int index, int value) {
205         throw new ReadOnlyBufferException();
206     }
207 
208     @Override
209     protected void _setByte(int index, int value) {
210         throw new ReadOnlyBufferException();
211     }
212 
213     @Override
214     public ByteBuf setShort(int index, int value) {
215         throw new ReadOnlyBufferException();
216     }
217 
218     @Override
219     protected void _setShort(int index, int value) {
220         throw new ReadOnlyBufferException();
221     }
222 
223     @Override
224     public ByteBuf setShortLE(int index, int value) {
225         throw new ReadOnlyBufferException();
226     }
227 
228     @Override
229     protected void _setShortLE(int index, int value) {
230         throw new ReadOnlyBufferException();
231     }
232 
233     @Override
234     public ByteBuf setMedium(int index, int value) {
235         throw new ReadOnlyBufferException();
236     }
237 
238     @Override
239     protected void _setMedium(int index, int value) {
240         throw new ReadOnlyBufferException();
241     }
242 
243     @Override
244     public ByteBuf setMediumLE(int index, int value) {
245         throw new ReadOnlyBufferException();
246     }
247 
248     @Override
249     protected void _setMediumLE(int index, int value) {
250         throw new ReadOnlyBufferException();
251     }
252 
253     @Override
254     public ByteBuf setInt(int index, int value) {
255         throw new ReadOnlyBufferException();
256     }
257 
258     @Override
259     protected void _setInt(int index, int value) {
260         throw new ReadOnlyBufferException();
261     }
262 
263     @Override
264     public ByteBuf setIntLE(int index, int value) {
265         throw new ReadOnlyBufferException();
266     }
267 
268     @Override
269     protected void _setIntLE(int index, int value) {
270         throw new ReadOnlyBufferException();
271     }
272 
273     @Override
274     public ByteBuf setLong(int index, long value) {
275         throw new ReadOnlyBufferException();
276     }
277 
278     @Override
279     protected void _setLong(int index, long value) {
280         throw new ReadOnlyBufferException();
281     }
282 
283     @Override
284     public ByteBuf setLongLE(int index, long value) {
285         throw new ReadOnlyBufferException();
286     }
287 
288     @Override
289     protected void _setLongLE(int index, long value) {
290         throw new ReadOnlyBufferException();
291     }
292 
293     @Override
294     public int capacity() {
295         return maxCapacity();
296     }
297 
298     @Override
299     public ByteBuf capacity(int newCapacity) {
300         throw new ReadOnlyBufferException();
301     }
302 
303     @Override
304     public ByteBufAllocator alloc() {
305         return allocator;
306     }
307 
308     @Override
309     public ByteOrder order() {
310         return ByteOrder.BIG_ENDIAN;
311     }
312 
313     @Override
314     public ByteBuf unwrap() {
315         return null;
316     }
317 
318     @Override
319     public boolean isReadOnly() {
320         return buffer.isReadOnly();
321     }
322 
323     @Override
324     public boolean isDirect() {
325         return buffer.isDirect();
326     }
327 
328     @Override
329     public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
330         ensureAccessible();
331         if (length == 0) {
332             return this;
333         }
334 
335         if (buffer.hasArray()) {
336             out.write(buffer.array(), index + buffer.arrayOffset(), length);
337         } else {
338             byte[] tmp = new byte[length];
339             ByteBuffer tmpBuf = internalNioBuffer();
340             tmpBuf.clear().position(index);
341             tmpBuf.get(tmp);
342             out.write(tmp);
343         }
344         return this;
345     }
346 
347     @Override
348     public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
349         ensureAccessible();
350         if (length == 0) {
351             return 0;
352         }
353 
354         ByteBuffer tmpBuf = internalNioBuffer();
355         tmpBuf.clear().position(index).limit(index + length);
356         return out.write(tmpBuf);
357     }
358 
359     @Override
360     public int getBytes(int index, FileChannel out, long position, int length) throws IOException {
361         ensureAccessible();
362         if (length == 0) {
363             return 0;
364         }
365 
366         ByteBuffer tmpBuf = internalNioBuffer();
367         tmpBuf.clear().position(index).limit(index + length);
368         return out.write(tmpBuf, position);
369     }
370 
371     @Override
372     public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
373         throw new ReadOnlyBufferException();
374     }
375 
376     @Override
377     public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
378         throw new ReadOnlyBufferException();
379     }
380 
381     @Override
382     public ByteBuf setBytes(int index, ByteBuffer src) {
383         throw new ReadOnlyBufferException();
384     }
385 
386     @Override
387     public int setBytes(int index, InputStream in, int length) throws IOException {
388         throw new ReadOnlyBufferException();
389     }
390 
391     @Override
392     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
393         throw new ReadOnlyBufferException();
394     }
395 
396     @Override
397     public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
398         throw new ReadOnlyBufferException();
399     }
400 
401     protected final ByteBuffer internalNioBuffer() {
402         ByteBuffer tmpNioBuf = this.tmpNioBuf;
403         if (tmpNioBuf == null) {
404             this.tmpNioBuf = tmpNioBuf = buffer.duplicate();
405         }
406         return tmpNioBuf;
407     }
408 
409     @Override
410     public ByteBuf copy(int index, int length) {
411         ensureAccessible();
412         ByteBuffer src;
413         try {
414             src = (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
415         } catch (IllegalArgumentException ignored) {
416             throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length));
417         }
418 
419         ByteBuf dst = src.isDirect() ? alloc().directBuffer(length) : alloc().heapBuffer(length);
420         dst.writeBytes(src);
421         return dst;
422     }
423 
424     @Override
425     public int nioBufferCount() {
426         return 1;
427     }
428 
429     @Override
430     public ByteBuffer[] nioBuffers(int index, int length) {
431         return new ByteBuffer[] { nioBuffer(index, length) };
432     }
433 
434     @Override
435     public ByteBuffer nioBuffer(int index, int length) {
436         return (ByteBuffer) buffer.duplicate().position(index).limit(index + length);
437     }
438 
439     @Override
440     public ByteBuffer internalNioBuffer(int index, int length) {
441         ensureAccessible();
442         return (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
443     }
444 
445     @Override
446     public boolean hasArray() {
447         return buffer.hasArray();
448     }
449 
450     @Override
451     public byte[] array() {
452         return buffer.array();
453     }
454 
455     @Override
456     public int arrayOffset() {
457         return buffer.arrayOffset();
458     }
459 
460     @Override
461     public boolean hasMemoryAddress() {
462         return false;
463     }
464 
465     @Override
466     public long memoryAddress() {
467         throw new UnsupportedOperationException();
468     }
469 }