001 /*
002 * Copyright (C) 2008 Trustin Heuiseung Lee
003 *
004 * This library is free software; you can redistribute it and/or
005 * modify it under the terms of the GNU Lesser General Public
006 * License as published by the Free Software Foundation; either
007 * version 2.1 of the License, or (at your option) any later version.
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this library; if not, write to the Free Software
016 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA
017 */
018 package net.gleamynode.netty.buffer;
019
020 import java.io.EOFException;
021 import java.io.IOException;
022 import java.io.InputStream;
023 import java.io.OutputStream;
024 import java.nio.ByteBuffer;
025 import java.nio.ByteOrder;
026 import java.nio.channels.GatheringByteChannel;
027 import java.nio.channels.ScatteringByteChannel;
028
029
030 public class ByteBufferBackedChannelBuffer extends AbstractChannelBuffer {
031
032 private final ByteBuffer buffer;
033 private final int capacity;
034
035 public ByteBufferBackedChannelBuffer(ByteBuffer buffer) {
036 if (buffer == null) {
037 throw new NullPointerException("buffer");
038 }
039
040 this.buffer = buffer.slice();
041 capacity = buffer.remaining();
042 writerIndex(capacity);
043 }
044
045 private ByteBufferBackedChannelBuffer(ByteBufferBackedChannelBuffer buffer) {
046 this.buffer = buffer.buffer;
047 capacity = buffer.capacity;
048 setIndex(buffer.readerIndex(), buffer.writerIndex());
049 }
050
051 public ByteOrder order() {
052 return buffer.order();
053 }
054
055 public int capacity() {
056 return capacity;
057 }
058
059 public byte getByte(int index) {
060 return buffer.get(index);
061 }
062
063 public short getShort(int index) {
064 return buffer.getShort(index);
065 }
066
067 public int getMedium(int index) {
068 return (getByte(index) & 0xff) << 16 |
069 (getByte(index+1) & 0xff) << 8 |
070 (getByte(index+2) & 0xff) << 0;
071 }
072
073 public int getInt(int index) {
074 return buffer.getInt(index);
075 }
076
077 public long getLong(int index) {
078 return buffer.getLong(index);
079 }
080
081 public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {
082 if (dst instanceof ByteBufferBackedChannelBuffer) {
083 ByteBufferBackedChannelBuffer bbdst = (ByteBufferBackedChannelBuffer) dst;
084 ByteBuffer data = bbdst.buffer.duplicate();
085
086 data.limit(dstIndex + length).position(dstIndex);
087 getBytes(index, data);
088 } else if (buffer.hasArray()) {
089 dst.setBytes(dstIndex, buffer.array(), index + buffer.arrayOffset(), length);
090 } else {
091 dst.setBytes(dstIndex, this, index, length);
092 }
093 }
094
095 public void getBytes(int index, byte[] dst, int dstIndex, int length) {
096 ByteBuffer data = buffer.duplicate();
097 try {
098 data.limit(index + length).position(index);
099 } catch (IllegalArgumentException e) {
100 throw new IndexOutOfBoundsException();
101 }
102 data.get(dst, dstIndex, length);
103 }
104
105 public void getBytes(int index, ByteBuffer dst) {
106 ByteBuffer data = buffer.duplicate();
107 int bytesToCopy = Math.min(capacity() - index, dst.remaining());
108 try {
109 data.limit(index + bytesToCopy).position(index);
110 } catch (IllegalArgumentException e) {
111 throw new IndexOutOfBoundsException();
112 }
113 dst.put(data);
114 }
115
116 public void setByte(int index, byte value) {
117 buffer.put(index, value);
118 }
119
120 public void setShort(int index, short value) {
121 buffer.putShort(index, value);
122 }
123
124 public void setMedium(int index, int value) {
125 setByte(index, (byte) (value >>> 16));
126 setByte(index+1, (byte) (value >>> 8));
127 setByte(index+2, (byte) (value >>> 0));
128 }
129
130 public void setInt(int index, int value) {
131 buffer.putInt(index, value);
132 }
133
134 public void setLong(int index, long value) {
135 buffer.putLong(index, value);
136 }
137
138 public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {
139 if (src instanceof ByteBufferBackedChannelBuffer) {
140 ByteBufferBackedChannelBuffer bbsrc = (ByteBufferBackedChannelBuffer) src;
141 ByteBuffer data = bbsrc.buffer.duplicate();
142
143 data.limit(srcIndex + length).position(srcIndex);
144 setBytes(index, data);
145 } else if (buffer.hasArray()) {
146 src.getBytes(srcIndex, buffer.array(), index + buffer.arrayOffset(), length);
147 } else {
148 src.getBytes(srcIndex, this, index, length);
149 }
150 }
151
152 public void setBytes(int index, byte[] src, int srcIndex, int length) {
153 ByteBuffer data = buffer.duplicate();
154 data.limit(index + length).position(index);
155 data.put(src, srcIndex, length);
156 }
157
158 public void setBytes(int index, ByteBuffer src) {
159 ByteBuffer data = buffer.duplicate();
160 data.limit(index + src.remaining()).position(index);
161 data.put(src);
162 }
163
164 public void getBytes(int index, OutputStream out, int length) throws IOException {
165 if (length == 0) {
166 return;
167 }
168
169 if (!buffer.isReadOnly() && buffer.hasArray()) {
170 out.write(
171 buffer.array(),
172 index + buffer.arrayOffset(),
173 length);
174 } else {
175 byte[] tmp = new byte[length];
176 ((ByteBuffer) buffer.duplicate().position(index)).get(tmp);
177 out.write(tmp);
178 }
179 }
180
181 public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
182 if (length == 0) {
183 return 0;
184 }
185
186 return out.write((ByteBuffer) buffer.duplicate().position(index).limit(index + length));
187 }
188
189 public void setBytes(int index, InputStream in, int length)
190 throws IOException {
191 if (length == 0) {
192 return;
193 }
194
195 if (!buffer.isReadOnly() && buffer.hasArray()) {
196 index += buffer.arrayOffset();
197 do {
198 int readBytes = in.read(
199 buffer.array(), index, length);
200 if (readBytes < 0) {
201 throw new EOFException();
202 }
203 index += readBytes;
204 length -= readBytes;
205 } while (length > 0);
206 } else {
207 byte[] tmp = new byte[length];
208 for (int i = 0; i < tmp.length;) {
209 int readBytes = in.read(tmp, i, tmp.length - i);
210 if (readBytes < 0) {
211 throw new EOFException();
212 }
213 i += readBytes;
214 }
215 ((ByteBuffer) buffer.duplicate().position(index)).get(tmp);
216 }
217 }
218
219 public int setBytes(int index, ScatteringByteChannel in, int length)
220 throws IOException {
221 return in.read((ByteBuffer) buffer.duplicate().limit(index + length).position(index));
222 }
223
224 public ByteBuffer toByteBuffer(int index, int length) {
225 if (index == 0 && length == capacity()) {
226 return buffer.duplicate();
227 } else {
228 return ((ByteBuffer) buffer.duplicate().position(index).limit(index + length)).slice();
229 }
230 }
231
232 public ChannelBuffer slice(int index, int length) {
233 if (index == 0 && length == capacity()) {
234 return duplicate();
235 } else {
236 return new ByteBufferBackedChannelBuffer(
237 ((ByteBuffer) buffer.duplicate().position(index).limit(index + length)));
238 }
239 }
240
241 public ChannelBuffer duplicate() {
242 return new ByteBufferBackedChannelBuffer(this);
243 }
244
245 public ChannelBuffer copy(int index, int length) {
246 ByteBuffer src = (ByteBuffer) buffer.duplicate().position(index).limit(index + length);
247 ByteBuffer dst = buffer.isDirect() ? ByteBuffer.allocateDirect(length) : ByteBuffer.allocate(length);
248 dst.put(src);
249 dst.clear();
250 return new ByteBufferBackedChannelBuffer(dst);
251 }
252 }