View Javadoc

1   /*
2    * Copyright 2009 Red Hat, Inc.
3    *
4    * Red Hat licenses this file to you under the Apache License, version 2.0
5    * (the "License"); you may not use this file except in compliance with the
6    * 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.channels.GatheringByteChannel;
23  import java.nio.channels.ScatteringByteChannel;
24  import java.nio.charset.Charset;
25  import java.util.NoSuchElementException;
26  
27  
28  /**
29   * A skeletal implementation of a buffer.
30   *
31   * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
32   * @author <a href="http://gleamynode.net/">Trustin Lee</a>
33   *
34   * @version $Rev: 2211 $, $Date: 2010-03-04 15:34:00 +0900 (Thu, 04 Mar 2010) $
35   */
36  public abstract class AbstractChannelBuffer implements ChannelBuffer {
37  
38      private int readerIndex;
39      private int writerIndex;
40      private int markedReaderIndex;
41      private int markedWriterIndex;
42  
43      public int readerIndex() {
44          return readerIndex;
45      }
46  
47      public void readerIndex(int readerIndex) {
48          if (readerIndex < 0 || readerIndex > writerIndex) {
49              throw new IndexOutOfBoundsException();
50          }
51          this.readerIndex = readerIndex;
52      }
53  
54      public int writerIndex() {
55          return writerIndex;
56      }
57  
58      public void writerIndex(int writerIndex) {
59          if (writerIndex < readerIndex || writerIndex > capacity()) {
60              throw new IndexOutOfBoundsException();
61          }
62          this.writerIndex = writerIndex;
63      }
64  
65      public void setIndex(int readerIndex, int writerIndex) {
66          if (readerIndex < 0 || readerIndex > writerIndex || writerIndex > capacity()) {
67              throw new IndexOutOfBoundsException();
68          }
69          this.readerIndex = readerIndex;
70          this.writerIndex = writerIndex;
71      }
72  
73      public void clear() {
74          readerIndex = writerIndex = 0;
75      }
76  
77      public boolean readable() {
78          return readableBytes() > 0;
79      }
80  
81      public boolean writable() {
82          return writableBytes() > 0;
83      }
84  
85      public int readableBytes() {
86          return writerIndex - readerIndex;
87      }
88  
89      public int writableBytes() {
90          return capacity() - writerIndex;
91      }
92  
93      public void markReaderIndex() {
94          markedReaderIndex = readerIndex;
95      }
96  
97      public void resetReaderIndex() {
98          readerIndex(markedReaderIndex);
99      }
100 
101     public void markWriterIndex() {
102         markedWriterIndex = writerIndex;
103     }
104 
105     public void resetWriterIndex() {
106         writerIndex = markedWriterIndex;
107     }
108 
109     public void discardReadBytes() {
110         if (readerIndex == 0) {
111             return;
112         }
113         setBytes(0, this, readerIndex, writerIndex - readerIndex);
114         writerIndex -= readerIndex;
115         markedReaderIndex = Math.max(markedReaderIndex - readerIndex, 0);
116         markedWriterIndex = Math.max(markedWriterIndex - readerIndex, 0);
117         readerIndex = 0;
118     }
119 
120     public void ensureWritableBytes(int writableBytes) {
121         if (writableBytes > writableBytes()) {
122             throw new IndexOutOfBoundsException();
123         }
124     }
125 
126     public short getUnsignedByte(int index) {
127         return (short) (getByte(index) & 0xFF);
128     }
129 
130     public int getUnsignedShort(int index) {
131         return getShort(index) & 0xFFFF;
132     }
133 
134     public int getMedium(int index) {
135         int value = getUnsignedMedium(index);
136         if ((value & 0x800000) != 0) {
137             value |= 0xff000000;
138         }
139         return value;
140     }
141 
142     public long getUnsignedInt(int index) {
143         return getInt(index) & 0xFFFFFFFFL;
144     }
145 
146     public char getChar(int index) {
147         return (char) getShort(index);
148     }
149 
150     public float getFloat(int index) {
151         return Float.intBitsToFloat(getInt(index));
152     }
153 
154     public double getDouble(int index) {
155         return Double.longBitsToDouble(getLong(index));
156     }
157 
158     public void getBytes(int index, byte[] dst) {
159         getBytes(index, dst, 0, dst.length);
160     }
161 
162     public void getBytes(int index, ChannelBuffer dst) {
163         getBytes(index, dst, dst.writableBytes());
164     }
165 
166     public void getBytes(int index, ChannelBuffer dst, int length) {
167         if (length > dst.writableBytes()) {
168             throw new IndexOutOfBoundsException();
169         }
170         getBytes(index, dst, dst.writerIndex(), length);
171         dst.writerIndex(dst.writerIndex() + length);
172     }
173 
174     public void setChar(int index, int value) {
175         setShort(index, value);
176     }
177 
178     public void setFloat(int index, float value) {
179         setInt(index, Float.floatToRawIntBits(value));
180     }
181 
182     public void setDouble(int index, double value) {
183         setLong(index, Double.doubleToRawLongBits(value));
184     }
185 
186     public void setBytes(int index, byte[] src) {
187         setBytes(index, src, 0, src.length);
188     }
189 
190     public void setBytes(int index, ChannelBuffer src) {
191         setBytes(index, src, src.readableBytes());
192     }
193 
194     public void setBytes(int index, ChannelBuffer src, int length) {
195         if (length > src.readableBytes()) {
196             throw new IndexOutOfBoundsException();
197         }
198         setBytes(index, src, src.readerIndex(), length);
199         src.readerIndex(src.readerIndex() + length);
200     }
201 
202     public void setZero(int index, int length) {
203         if (length == 0) {
204             return;
205         }
206         if (length < 0) {
207             throw new IllegalArgumentException(
208                     "length must be 0 or greater than 0.");
209         }
210 
211         int nLong = length >>> 3;
212         int nBytes = length & 7;
213         for (int i = nLong; i > 0; i --) {
214             setLong(index, 0);
215             index += 8;
216         }
217         if (nBytes == 4) {
218             setInt(index, 0);
219         } else if (nBytes < 4) {
220             for (int i = nBytes; i > 0; i --) {
221                 setByte(index, (byte) 0);
222                 index ++;
223             }
224         } else {
225             setInt(index, 0);
226             index += 4;
227             for (int i = nBytes - 4; i > 0; i --) {
228                 setByte(index, (byte) 0);
229                 index ++;
230             }
231         }
232     }
233 
234     public byte readByte() {
235         if (readerIndex == writerIndex) {
236             throw new IndexOutOfBoundsException();
237         }
238         return getByte(readerIndex ++);
239     }
240 
241     public short readUnsignedByte() {
242         return (short) (readByte() & 0xFF);
243     }
244 
245     public short readShort() {
246         checkReadableBytes(2);
247         short v = getShort(readerIndex);
248         readerIndex += 2;
249         return v;
250     }
251 
252     public int readUnsignedShort() {
253         return readShort() & 0xFFFF;
254     }
255 
256     public int readMedium() {
257         int value = readUnsignedMedium();
258         if ((value & 0x800000) != 0) {
259             value |= 0xff000000;
260         }
261         return value;
262     }
263 
264     public int readUnsignedMedium() {
265         checkReadableBytes(3);
266         int v = getUnsignedMedium(readerIndex);
267         readerIndex += 3;
268         return v;
269     }
270 
271     public int readInt() {
272         checkReadableBytes(4);
273         int v = getInt(readerIndex);
274         readerIndex += 4;
275         return v;
276     }
277 
278     public long readUnsignedInt() {
279         return readInt() & 0xFFFFFFFFL;
280     }
281 
282     public long readLong() {
283         checkReadableBytes(8);
284         long v = getLong(readerIndex);
285         readerIndex += 8;
286         return v;
287     }
288 
289     public char readChar() {
290         return (char) readShort();
291     }
292 
293     public float readFloat() {
294         return Float.intBitsToFloat(readInt());
295     }
296 
297     public double readDouble() {
298         return Double.longBitsToDouble(readLong());
299     }
300 
301     public ChannelBuffer readBytes(int length) {
302         checkReadableBytes(length);
303         if (length == 0) {
304             return ChannelBuffers.EMPTY_BUFFER;
305         }
306         ChannelBuffer buf = factory().getBuffer(order(), length);
307         buf.writeBytes(this, readerIndex, length);
308         readerIndex += length;
309         return buf;
310     }
311 
312     @Deprecated
313     public ChannelBuffer readBytes(ChannelBufferIndexFinder endIndexFinder) {
314         int endIndex = indexOf(readerIndex, writerIndex, endIndexFinder);
315         if (endIndex < 0) {
316             throw new NoSuchElementException();
317         }
318         return readBytes(endIndex - readerIndex);
319     }
320 
321     public ChannelBuffer readSlice(int length) {
322         ChannelBuffer slice = slice(readerIndex, length);
323         readerIndex += length;
324         return slice;
325     }
326 
327     @Deprecated
328     public ChannelBuffer readSlice(ChannelBufferIndexFinder endIndexFinder) {
329         int endIndex = indexOf(readerIndex, writerIndex, endIndexFinder);
330         if (endIndex < 0) {
331             throw new NoSuchElementException();
332         }
333         return readSlice(endIndex - readerIndex);
334     }
335 
336     public void readBytes(byte[] dst, int dstIndex, int length) {
337         checkReadableBytes(length);
338         getBytes(readerIndex, dst, dstIndex, length);
339         readerIndex += length;
340     }
341 
342     public void readBytes(byte[] dst) {
343         readBytes(dst, 0, dst.length);
344     }
345 
346     public void readBytes(ChannelBuffer dst) {
347         readBytes(dst, dst.writableBytes());
348     }
349 
350     public void readBytes(ChannelBuffer dst, int length) {
351         if (length > dst.writableBytes()) {
352             throw new IndexOutOfBoundsException();
353         }
354         readBytes(dst, dst.writerIndex(), length);
355         dst.writerIndex(dst.writerIndex() + length);
356     }
357 
358     public void readBytes(ChannelBuffer dst, int dstIndex, int length) {
359         checkReadableBytes(length);
360         getBytes(readerIndex, dst, dstIndex, length);
361         readerIndex += length;
362     }
363 
364     public void readBytes(ByteBuffer dst) {
365         int length = dst.remaining();
366         checkReadableBytes(length);
367         getBytes(readerIndex, dst);
368         readerIndex += length;
369     }
370 
371     public int readBytes(GatheringByteChannel out, int length)
372             throws IOException {
373         checkReadableBytes(length);
374         int readBytes = getBytes(readerIndex, out, length);
375         readerIndex += readBytes;
376         return readBytes;
377     }
378 
379     public void readBytes(OutputStream out, int length) throws IOException {
380         checkReadableBytes(length);
381         getBytes(readerIndex, out, length);
382         readerIndex += length;
383     }
384 
385     public void skipBytes(int length) {
386         int newReaderIndex = readerIndex + length;
387         if (newReaderIndex > writerIndex) {
388             throw new IndexOutOfBoundsException();
389         }
390         readerIndex = newReaderIndex;
391     }
392 
393     @Deprecated
394     public int skipBytes(ChannelBufferIndexFinder firstIndexFinder) {
395         int oldReaderIndex = readerIndex;
396         int newReaderIndex = indexOf(oldReaderIndex, writerIndex, firstIndexFinder);
397         if (newReaderIndex < 0) {
398             throw new NoSuchElementException();
399         }
400         readerIndex(newReaderIndex);
401         return newReaderIndex - oldReaderIndex;
402     }
403 
404     public void writeByte(int value) {
405         setByte(writerIndex ++, value);
406     }
407 
408     public void writeShort(int value) {
409         setShort(writerIndex, value);
410         writerIndex += 2;
411     }
412 
413     public void writeMedium(int value) {
414         setMedium(writerIndex, value);
415         writerIndex += 3;
416     }
417 
418     public void writeInt(int value) {
419         setInt(writerIndex, value);
420         writerIndex += 4;
421     }
422 
423     public void writeLong(long value) {
424         setLong(writerIndex, value);
425         writerIndex += 8;
426     }
427 
428     public void writeChar(int value) {
429         writeShort(value);
430     }
431 
432     public void writeFloat(float value) {
433         writeInt(Float.floatToRawIntBits(value));
434     }
435 
436     public void writeDouble(double value) {
437         writeLong(Double.doubleToRawLongBits(value));
438     }
439 
440     public void writeBytes(byte[] src, int srcIndex, int length) {
441         setBytes(writerIndex, src, srcIndex, length);
442         writerIndex += length;
443     }
444 
445     public void writeBytes(byte[] src) {
446         writeBytes(src, 0, src.length);
447     }
448 
449     public void writeBytes(ChannelBuffer src) {
450         writeBytes(src, src.readableBytes());
451     }
452 
453     public void writeBytes(ChannelBuffer src, int length) {
454         if (length > src.readableBytes()) {
455             throw new IndexOutOfBoundsException();
456         }
457         writeBytes(src, src.readerIndex(), length);
458         src.readerIndex(src.readerIndex() + length);
459     }
460 
461     public void writeBytes(ChannelBuffer src, int srcIndex, int length) {
462         setBytes(writerIndex, src, srcIndex, length);
463         writerIndex += length;
464     }
465 
466     public void writeBytes(ByteBuffer src) {
467         int length = src.remaining();
468         setBytes(writerIndex, src);
469         writerIndex += length;
470     }
471 
472     public int writeBytes(InputStream in, int length)
473             throws IOException {
474         int writtenBytes = setBytes(writerIndex, in, length);
475         if (writtenBytes > 0) {
476             writerIndex += writtenBytes;
477         }
478         return writtenBytes;
479     }
480 
481     public int writeBytes(ScatteringByteChannel in, int length)
482             throws IOException {
483         int writtenBytes = setBytes(writerIndex, in, length);
484         if (writtenBytes > 0) {
485             writerIndex += writtenBytes;
486         }
487         return writtenBytes;
488     }
489 
490     public void writeZero(int length) {
491         if (length == 0) {
492             return;
493         }
494         if (length < 0) {
495             throw new IllegalArgumentException(
496                     "length must be 0 or greater than 0.");
497         }
498         int nLong = length >>> 3;
499         int nBytes = length & 7;
500         for (int i = nLong; i > 0; i --) {
501             writeLong(0);
502         }
503         if (nBytes == 4) {
504             writeInt(0);
505         } else if (nBytes < 4) {
506             for (int i = nBytes; i > 0; i --) {
507                 writeByte((byte) 0);
508             }
509         } else {
510             writeInt(0);
511             for (int i = nBytes - 4; i > 0; i --) {
512                 writeByte((byte) 0);
513             }
514         }
515     }
516 
517     public ChannelBuffer copy() {
518         return copy(readerIndex, readableBytes());
519     }
520 
521     public ChannelBuffer slice() {
522         return slice(readerIndex, readableBytes());
523     }
524 
525     public ByteBuffer toByteBuffer() {
526         return toByteBuffer(readerIndex, readableBytes());
527     }
528 
529     public ByteBuffer[] toByteBuffers() {
530         return toByteBuffers(readerIndex, readableBytes());
531     }
532 
533     public ByteBuffer[] toByteBuffers(int index, int length) {
534         return new ByteBuffer[] { toByteBuffer(index, length) };
535     }
536 
537     public String toString(Charset charset) {
538         return toString(readerIndex, readableBytes(), charset);
539     }
540 
541     public String toString(int index, int length, Charset charset) {
542         if (length == 0) {
543             return "";
544         }
545 
546         return ChannelBuffers.decodeString(
547                 toByteBuffer(index, length), charset);
548     }
549 
550     @Deprecated
551     public String toString(int index, int length, String charsetName,
552             ChannelBufferIndexFinder terminatorFinder) {
553         if (terminatorFinder == null) {
554             return toString(index, length, charsetName);
555         }
556 
557         int terminatorIndex = indexOf(index, index + length, terminatorFinder);
558         if (terminatorIndex < 0) {
559             return toString(index, length, charsetName);
560         }
561 
562         return toString(index, terminatorIndex - index, charsetName);
563     }
564 
565     @Deprecated
566     public String toString(int index, int length, String charsetName) {
567         return toString(index, length, Charset.forName(charsetName));
568     }
569 
570     @Deprecated
571     public String toString(String charsetName,
572             ChannelBufferIndexFinder terminatorFinder) {
573         return toString(readerIndex, readableBytes(), charsetName, terminatorFinder);
574     }
575 
576     @Deprecated
577     public String toString(String charsetName) {
578         return toString(Charset.forName(charsetName));
579     }
580 
581     public int indexOf(int fromIndex, int toIndex, byte value) {
582         return ChannelBuffers.indexOf(this, fromIndex, toIndex, value);
583     }
584 
585     public int indexOf(int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder) {
586         return ChannelBuffers.indexOf(this, fromIndex, toIndex, indexFinder);
587     }
588 
589     public int bytesBefore(byte value) {
590         return bytesBefore(readerIndex(), readableBytes(), value);
591     }
592 
593     public int bytesBefore(ChannelBufferIndexFinder indexFinder) {
594         return bytesBefore(readerIndex(), readableBytes(), indexFinder);
595     }
596 
597     public int bytesBefore(int length, byte value) {
598         checkReadableBytes(length);
599         return bytesBefore(readerIndex(), length, value);
600     }
601 
602     public int bytesBefore(int length, ChannelBufferIndexFinder indexFinder) {
603         checkReadableBytes(length);
604         return bytesBefore(readerIndex(), length, indexFinder);
605     }
606 
607     public int bytesBefore(int index, int length, byte value) {
608         int endIndex = indexOf(index, index + length, value);
609         if (endIndex < 0) {
610             return -1;
611         }
612         return endIndex - index;
613     }
614 
615     public int bytesBefore(int index, int length,
616             ChannelBufferIndexFinder indexFinder) {
617         int endIndex = indexOf(index, index + length, indexFinder);
618         if (endIndex < 0) {
619             return -1;
620         }
621         return endIndex - index;
622     }
623 
624     @Override
625     public int hashCode() {
626         return ChannelBuffers.hashCode(this);
627     }
628 
629     @Override
630     public boolean equals(Object o) {
631         if (!(o instanceof ChannelBuffer)) {
632             return false;
633         }
634         return ChannelBuffers.equals(this, (ChannelBuffer) o);
635     }
636 
637     public int compareTo(ChannelBuffer that) {
638         return ChannelBuffers.compare(this, that);
639     }
640 
641     @Override
642     public String toString() {
643         return getClass().getSimpleName() + '(' +
644                "ridx=" + readerIndex + ", " +
645                "widx=" + writerIndex + ", " +
646                "cap=" + capacity() +
647                ')';
648     }
649 
650     /**
651      * Throws an {@link IndexOutOfBoundsException} if the current
652      * {@linkplain #readableBytes() readable bytes} of this buffer is less
653      * than the specified value.
654      */
655     protected void checkReadableBytes(int minimumReadableBytes) {
656         if (readableBytes() < minimumReadableBytes) {
657             throw new IndexOutOfBoundsException();
658         }
659     }
660 }