diff --git a/src/main/java/org/jboss/netty/buffer/AbstractChannelBuffer.java b/src/main/java/org/jboss/netty/buffer/AbstractChannelBuffer.java index 19b8bb0aab..0ba46f77ff 100644 --- a/src/main/java/org/jboss/netty/buffer/AbstractChannelBuffer.java +++ b/src/main/java/org/jboss/netty/buffer/AbstractChannelBuffer.java @@ -583,6 +583,41 @@ public abstract class AbstractChannelBuffer implements ChannelBuffer { return ChannelBuffers.indexOf(this, fromIndex, toIndex, indexFinder); } + public int bytesBefore(byte value) { + return bytesBefore(readerIndex(), readableBytes(), value); + } + + public int bytesBefore(ChannelBufferIndexFinder indexFinder) { + return bytesBefore(readerIndex(), readableBytes(), indexFinder); + } + + public int bytesBefore(int length, byte value) { + checkReadableBytes(length); + return bytesBefore(readerIndex(), length, value); + } + + public int bytesBefore(int length, ChannelBufferIndexFinder indexFinder) { + checkReadableBytes(length); + return bytesBefore(readerIndex(), length, indexFinder); + } + + public int bytesBefore(int index, int length, byte value) { + int endIndex = indexOf(index, index + length, value); + if (endIndex < 0) { + return -1; + } + return endIndex - index; + } + + public int bytesBefore(int index, int length, + ChannelBufferIndexFinder indexFinder) { + int endIndex = indexOf(index, index + length, indexFinder); + if (endIndex < 0) { + return -1; + } + return endIndex - index; + } + @Override public int hashCode() { return ChannelBuffers.hashCode(this); diff --git a/src/main/java/org/jboss/netty/buffer/ChannelBuffer.java b/src/main/java/org/jboss/netty/buffer/ChannelBuffer.java index 197dfe9724..273452027a 100644 --- a/src/main/java/org/jboss/netty/buffer/ChannelBuffer.java +++ b/src/main/java/org/jboss/netty/buffer/ChannelBuffer.java @@ -24,7 +24,6 @@ import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; -import java.util.NoSuchElementException; /** * A random and sequential accessible sequence of zero or more bytes (octets). @@ -176,10 +175,13 @@ import java.util.NoSuchElementException; * *
+ * If you are decoding variable length data such as NUL-terminated string, you + * will find {@link #bytesBefore(byte)} also useful. * *
+ * This method does not modify {@code readerIndex} or {@code writerIndex} of + * this buffer. + * + * @return the number of bytes between the current {@code readerIndex} + * and the first occurrence if found. {@code -1} otherwise. + */ + int bytesBefore(byte value); + + /** + * Locates the first place where the specified {@code indexFinder} returns + * {@code true}. The search takes place from the current {@code readerIndex} + * (inclusive) to the current {@code writerIndex}. + *
+ * This method does not modify {@code readerIndex} or {@code writerIndex} of + * this buffer. + * + * @return the number of bytes between the current {@code readerIndex} + * and the first place where the {@code indexFinder} returned + * {@code true}. {@code -1} if the {@code indexFinder} did not + * return {@code true} at all. + */ + int bytesBefore(ChannelBufferIndexFinder indexFinder); + + /** + * Locates the first occurrence of the specified {@code value} in this + * buffer. The search starts from the current {@code readerIndex} + * (inclusive) and lasts for the specified {@code length}. + *
+ * This method does not modify {@code readerIndex} or {@code writerIndex} of + * this buffer. + * + * @return the number of bytes between the current {@code readerIndex} + * and the first occurrence if found. {@code -1} otherwise. + * + * @throws IndexOutOfBoundsException + * if {@code length} is greater than {@code this.readableBytes} + */ + int bytesBefore(int length, byte value); + + /** + * Locates the first place where the specified {@code indexFinder} returns + * {@code true}. The search starts the current {@code readerIndex} + * (inclusive) and lasts for the specified {@code length}. + *
+ * This method does not modify {@code readerIndex} or {@code writerIndex} of + * this buffer. + * + * @return the number of bytes between the current {@code readerIndex} + * and the first place where the {@code indexFinder} returned + * {@code true}. {@code -1} if the {@code indexFinder} did not + * return {@code true} at all. + * + * @throws IndexOutOfBoundsException + * if {@code length} is greater than {@code this.readableBytes} + */ + int bytesBefore(int length, ChannelBufferIndexFinder indexFinder); + + /** + * Locates the first occurrence of the specified {@code value} in this + * buffer. The search starts from the specified {@code index} (inclusive) + * and lasts for the specified {@code length}. + *
+ * This method does not modify {@code readerIndex} or {@code writerIndex} of + * this buffer. + * + * @return the number of bytes between the specified {@code index} + * and the first occurrence if found. {@code -1} otherwise. + * + * @throws IndexOutOfBoundsException + * if {@code index + length} is greater than {@code this.capacity} + */ + int bytesBefore(int index, int length, byte value); + + /** + * Locates the first place where the specified {@code indexFinder} returns + * {@code true}. The search starts the specified {@code index} (inclusive) + * and lasts for the specified {@code length}. + *
+ * This method does not modify {@code readerIndex} or {@code writerIndex} of
+ * this buffer.
+ *
+ * @return the number of bytes between the specified {@code index}
+ * and the first place where the {@code indexFinder} returned
+ * {@code true}. {@code -1} if the {@code indexFinder} did not
+ * return {@code true} at all.
+ *
+ * @throws IndexOutOfBoundsException
+ * if {@code index + length} is greater than {@code this.capacity}
+ */
+ int bytesBefore(int index, int length, ChannelBufferIndexFinder indexFinder);
+
/**
* Returns a copy of this buffer's readable bytes. Modifying the content
* of the returned buffer or this buffer does not affect each other at all.
@@ -1636,20 +1710,20 @@ public interface ChannelBuffer extends Comparable
* This interface enables the sequential search for the data which meets more
* complex and dynamic condition than just a simple value matching. Please
- * refer to {@link ChannelBuffer#indexOf(int, int, ChannelBufferIndexFinder)},
- * {@link ChannelBuffer#readBytes(ChannelBufferIndexFinder)},
- * {@link ChannelBuffer#readSlice(ChannelBufferIndexFinder)}, and
- * {@link ChannelBuffer#skipBytes(ChannelBufferIndexFinder)}
+ * refer to {@link ChannelBuffer#indexOf(int, int, ChannelBufferIndexFinder)} and
+ * {@link ChannelBuffer#bytesBefore(int, int, ChannelBufferIndexFinder)}
* for more explanation.
*
* @author The Netty Project (netty-dev@lists.jboss.org)
diff --git a/src/main/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderBuffer.java b/src/main/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderBuffer.java
index 8abe2a242f..e40abe6fb8 100644
--- a/src/main/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderBuffer.java
+++ b/src/main/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderBuffer.java
@@ -223,6 +223,57 @@ class ReplayingDecoderBuffer implements ChannelBuffer {
return endIndex;
}
+ public int bytesBefore(byte value) {
+ int bytes = buffer.bytesBefore(value);
+ if (bytes < 0) {
+ throw REPLAY;
+ }
+ return bytes;
+ }
+
+ public int bytesBefore(ChannelBufferIndexFinder indexFinder) {
+ int bytes = buffer.bytesBefore(indexFinder);
+ if (bytes < 0) {
+ throw REPLAY;
+ }
+ return bytes;
+ }
+
+ public int bytesBefore(int length, byte value) {
+ checkReadableBytes(length);
+ int bytes = buffer.bytesBefore(length, value);
+ if (bytes < 0) {
+ throw REPLAY;
+ }
+ return bytes;
+ }
+
+ public int bytesBefore(int length, ChannelBufferIndexFinder indexFinder) {
+ checkReadableBytes(length);
+ int bytes = buffer.bytesBefore(length, indexFinder);
+ if (bytes < 0) {
+ throw REPLAY;
+ }
+ return bytes;
+ }
+
+ public int bytesBefore(int index, int length, byte value) {
+ int bytes = buffer.bytesBefore(index, length, value);
+ if (bytes < 0) {
+ throw REPLAY;
+ }
+ return bytes;
+ }
+
+ public int bytesBefore(int index, int length,
+ ChannelBufferIndexFinder indexFinder) {
+ int bytes = buffer.bytesBefore(index, length, indexFinder);
+ if (bytes < 0) {
+ throw REPLAY;
+ }
+ return bytes;
+ }
+
public void markReaderIndex() {
buffer.markReaderIndex();
}
diff --git a/src/test/java/org/jboss/netty/buffer/AbstractChannelBufferTest.java b/src/test/java/org/jboss/netty/buffer/AbstractChannelBufferTest.java
index 2d5de9fdb6..6c2f2a7ff9 100644
--- a/src/test/java/org/jboss/netty/buffer/AbstractChannelBufferTest.java
+++ b/src/test/java/org/jboss/netty/buffer/AbstractChannelBufferTest.java
@@ -1199,6 +1199,7 @@ public abstract class AbstractChannelBufferTest {
}
@Test
+ @SuppressWarnings("deprecation")
public void testSequentialCopiedBufferTransfer2() {
buffer.clear();
buffer.writeZero(buffer.capacity());
@@ -1249,6 +1250,7 @@ public abstract class AbstractChannelBufferTest {
}
@Test
+ @SuppressWarnings("deprecation")
public void testSequentialSlice2() {
buffer.clear();
buffer.writeZero(buffer.capacity());
@@ -1641,6 +1643,7 @@ public abstract class AbstractChannelBufferTest {
}
@Test
+ @SuppressWarnings("deprecation")
public void testSkipBytes2() {
buffer.clear();
buffer.writeZero(buffer.capacity());
diff --git a/src/test/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderTest.java b/src/test/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderTest.java
index 0414ca03dc..6d7a4118c1 100644
--- a/src/test/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderTest.java
+++ b/src/test/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderTest.java
@@ -63,7 +63,8 @@ public class ReplayingDecoderTest {
@Override
protected Object decode(ChannelHandlerContext ctx, Channel channel,
ChannelBuffer buffer, VoidEnum state) throws Exception {
- ChannelBuffer msg = buffer.readBytes(ChannelBufferIndexFinder.LF);
+ ChannelBuffer msg = buffer.readBytes(
+ buffer.bytesBefore(ChannelBufferIndexFinder.LF));
buffer.skipBytes(1);
return msg;
}