View Javadoc
1   /*
2    * Copyright 2012 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 org.jboss.netty.buffer;
17  
18  import java.io.IOException;
19  import java.io.InputStream;
20  import java.io.OutputStream;
21  import java.nio.ByteBuffer;
22  import java.nio.ByteOrder;
23  import java.nio.channels.GatheringByteChannel;
24  import java.nio.channels.ScatteringByteChannel;
25  
26  
27  /**
28   * A derived buffer which exposes its parent's sub-region only.  It is
29   * recommended to use {@link ChannelBuffer#slice()} and
30   * {@link ChannelBuffer#slice(int, int)} instead of calling the constructor
31   * explicitly.
32   */
33  public class SlicedChannelBuffer extends AbstractChannelBuffer implements WrappedChannelBuffer {
34  
35      private final ChannelBuffer buffer;
36      private final int adjustment;
37      private final int length;
38  
39      public SlicedChannelBuffer(ChannelBuffer buffer, int index, int length) {
40          if (index < 0 || index > buffer.capacity()) {
41              throw new IndexOutOfBoundsException("Invalid index of " + index
42                      + ", maximum is " + buffer.capacity());
43          }
44  
45          if (index + length > buffer.capacity()) {
46              throw new IndexOutOfBoundsException("Invalid combined index of "
47                      + (index + length) + ", maximum is " + buffer.capacity());
48          }
49  
50          this.buffer = buffer;
51          adjustment = index;
52          this.length = length;
53          writerIndex(length);
54      }
55  
56      public ChannelBuffer unwrap() {
57          return buffer;
58      }
59  
60      public ChannelBufferFactory factory() {
61          return buffer.factory();
62      }
63  
64      public ByteOrder order() {
65          return buffer.order();
66      }
67  
68      public boolean isDirect() {
69          return buffer.isDirect();
70      }
71  
72      public int capacity() {
73          return length;
74      }
75  
76      public boolean hasArray() {
77          return buffer.hasArray();
78      }
79  
80      public byte[] array() {
81          return buffer.array();
82      }
83  
84      public int arrayOffset() {
85          return buffer.arrayOffset() + adjustment;
86      }
87  
88      public byte getByte(int index) {
89          checkIndex(index);
90          return buffer.getByte(index + adjustment);
91      }
92  
93      public short getShort(int index) {
94          checkIndex(index, 2);
95          return buffer.getShort(index + adjustment);
96      }
97  
98      public int getUnsignedMedium(int index) {
99          checkIndex(index, 3);
100         return buffer.getUnsignedMedium(index + adjustment);
101     }
102 
103     public int getInt(int index) {
104         checkIndex(index, 4);
105         return buffer.getInt(index + adjustment);
106     }
107 
108     public long getLong(int index) {
109         checkIndex(index, 8);
110         return buffer.getLong(index + adjustment);
111     }
112 
113     public ChannelBuffer duplicate() {
114         ChannelBuffer duplicate = new SlicedChannelBuffer(buffer, adjustment, length);
115         duplicate.setIndex(readerIndex(), writerIndex());
116         return duplicate;
117     }
118 
119     public ChannelBuffer copy(int index, int length) {
120         checkIndex(index, length);
121         return buffer.copy(index + adjustment, length);
122     }
123 
124     public ChannelBuffer slice(int index, int length) {
125         checkIndex(index, length);
126         if (length == 0) {
127             return ChannelBuffers.EMPTY_BUFFER;
128         }
129         return new SlicedChannelBuffer(buffer, index + adjustment, length);
130     }
131 
132     public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {
133         checkIndex(index, length);
134         buffer.getBytes(index + adjustment, dst, dstIndex, length);
135     }
136 
137     public void getBytes(int index, byte[] dst, int dstIndex, int length) {
138         checkIndex(index, length);
139         buffer.getBytes(index + adjustment, dst, dstIndex, length);
140     }
141 
142     public void getBytes(int index, ByteBuffer dst) {
143         checkIndex(index, dst.remaining());
144         buffer.getBytes(index + adjustment, dst);
145     }
146 
147     public void setByte(int index, int value) {
148         checkIndex(index);
149         buffer.setByte(index + adjustment, value);
150     }
151 
152     public void setShort(int index, int value) {
153         checkIndex(index, 2);
154         buffer.setShort(index + adjustment, value);
155     }
156 
157     public void setMedium(int index, int value) {
158         checkIndex(index, 3);
159         buffer.setMedium(index + adjustment, value);
160     }
161 
162     public void setInt(int index, int value) {
163         checkIndex(index, 4);
164         buffer.setInt(index + adjustment, value);
165     }
166 
167     public void setLong(int index, long value) {
168         checkIndex(index, 8);
169         buffer.setLong(index + adjustment, value);
170     }
171 
172     public void setBytes(int index, byte[] src, int srcIndex, int length) {
173         checkIndex(index, length);
174         buffer.setBytes(index + adjustment, src, srcIndex, length);
175     }
176 
177     public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {
178         checkIndex(index, length);
179         buffer.setBytes(index + adjustment, src, srcIndex, length);
180     }
181 
182     public void setBytes(int index, ByteBuffer src) {
183         checkIndex(index, src.remaining());
184         buffer.setBytes(index + adjustment, src);
185     }
186 
187     public void getBytes(int index, OutputStream out, int length)
188             throws IOException {
189         checkIndex(index, length);
190         buffer.getBytes(index + adjustment, out, length);
191     }
192 
193     public int getBytes(int index, GatheringByteChannel out, int length)
194             throws IOException {
195         checkIndex(index, length);
196         return buffer.getBytes(index + adjustment, out, length);
197     }
198 
199     public int setBytes(int index, InputStream in, int length)
200             throws IOException {
201         checkIndex(index, length);
202         return buffer.setBytes(index + adjustment, in, length);
203     }
204 
205     public int setBytes(int index, ScatteringByteChannel in, int length)
206             throws IOException {
207         checkIndex(index, length);
208         return buffer.setBytes(index + adjustment, in, length);
209     }
210 
211     public ByteBuffer toByteBuffer(int index, int length) {
212         checkIndex(index, length);
213         return buffer.toByteBuffer(index + adjustment, length);
214     }
215 
216     private void checkIndex(int index) {
217         if (index < 0 || index >= capacity()) {
218             throw new IndexOutOfBoundsException("Invalid index: " + index
219                     + ", maximum is " + capacity());
220         }
221     }
222 
223     private void checkIndex(int startIndex, int length) {
224         if (length < 0) {
225             throw new IllegalArgumentException(
226                     "length is negative: " + length);
227         }
228         if (startIndex < 0) {
229             throw new IndexOutOfBoundsException("startIndex cannot be negative");
230         }
231         if (startIndex + length > capacity()) {
232             throw new IndexOutOfBoundsException("Index too big - Bytes needed: "
233                     + (startIndex + length) + ", maximum is " + capacity());
234         }
235     }
236 }