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    }