001    /**
002     *   GRANITE DATA SERVICES
003     *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004     *
005     *   This file is part of the Granite Data Services Platform.
006     *
007     *   Granite Data Services is free software; you can redistribute it and/or
008     *   modify it under the terms of the GNU Lesser General Public
009     *   License as published by the Free Software Foundation; either
010     *   version 2.1 of the License, or (at your option) any later version.
011     *
012     *   Granite Data Services is distributed in the hope that it will be useful,
013     *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014     *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015     *   General Public License for more details.
016     *
017     *   You should have received a copy of the GNU Lesser General Public
018     *   License along with this library; if not, write to the Free Software
019     *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020     *   USA, or see <http://www.gnu.org/licenses/>.
021     */
022    package org.granite.gravity.jbossweb;
023    
024    import java.io.IOException;
025    import java.io.InputStream;
026    
027    /**
028     * An unsynchronized input/output byte buffer that avoids useless byte array copies. 
029     * 
030     * @author Franck
031     */
032    public class ByteArrayCometIO extends InputStream implements CometIO {
033    
034            private static final byte[] BYTES_0 = new byte[0];
035    
036            protected final int initialCapacity;
037            protected byte buf[] = BYTES_0;
038            protected int pos = 0;
039            protected int mark = 0;
040            protected int count = 0;
041            
042            public ByteArrayCometIO() {
043                    this(2048);
044            }
045            
046            public ByteArrayCometIO(int initialCapacity) {
047                    if (initialCapacity < 1)
048                            throw new IllegalArgumentException("initialCapacity must be > 1: " + initialCapacity);
049                    this.initialCapacity = initialCapacity;
050            }
051    
052            public int readFully(InputStream is) throws IOException {
053                    try {
054                            int b = -1;
055                            
056                            while ((b = is.read()) != -1) {
057                                    if (count + 1 >= buf.length) {
058                                            if (buf.length > 0) {
059                                                    byte[] tmp = new byte[buf.length << 1];
060                                                    System.arraycopy(buf, 0, tmp, 0, buf.length);
061                                                    buf = tmp;
062                                            }
063                                            else
064                                                    buf = new byte[initialCapacity];
065                                    }
066                                    buf[count++] = (byte)b;
067                            }
068                            
069                            return count;
070                    }
071                    finally {
072                            is.close();
073                    }
074            }
075    
076            public boolean readAvailable(InputStream is) throws IOException {
077                    boolean eof = false;
078                    
079                    try {
080                            int available = -1;
081                            while ((available = is.available()) > 0) {
082            
083                        if (count > 0) {
084                            byte[] newBytes = new byte[available + count + 1];
085                            System.arraycopy(buf, 0, newBytes, 0, count);
086                            buf = newBytes;
087                        }
088                        else
089                            buf = new byte[available + 1];
090            
091                        if (is.read(buf, count, available) != available)
092                            throw new IOException("Could not read available bytes: " + available);
093                        
094                        count += available;
095                    }
096                            
097                            int b = is.read();
098                            if (b == -1) {
099                                    eof = true;
100                                    return false;
101                            }
102                            
103                            buf[buf.length - 1] = (byte)b;
104                            count++;
105                            
106                            return true;
107                    }
108                    finally {
109                            if (eof)
110                                    is.close();
111                    }
112            }
113            
114            public InputStream getInputStream() throws IOException {
115                    return this;
116            }
117    
118            @Override
119            public int read() throws IOException {
120                    return (pos < count) ? (buf[pos++] & 0xff) : -1;
121            }
122        
123            @Override
124            public int read(byte b[], int off, int len) {
125            if (b == null)
126                throw new NullPointerException();
127            
128            if (off < 0 || len < 0 || len > b.length - off)
129                throw new IndexOutOfBoundsException();
130    
131            if (pos >= count)
132                return -1;
133    
134            if (pos + len > count)
135                len = count - pos;
136    
137            if (len <= 0)
138                return 0;
139    
140            System.arraycopy(buf, pos, b, off, len);
141            pos += len;
142            return len;
143            }
144    
145            @Override
146        public long skip(long n) {
147            if (pos + n > count)
148                n = count - pos;
149    
150            if (n < 0)
151                return 0;
152    
153            pos += n;
154            return n;
155        }
156    
157            @Override
158        public int available() {
159            return count - pos;
160        }
161    
162            @Override
163        public boolean markSupported() {
164            return true;
165        }
166            
167            @Override
168            public void mark(int readAheadLimit) {
169                    mark = pos;
170            }
171    
172            @Override
173        public void reset() {
174            pos = mark;
175        }
176    
177        @Override
178            public void close() throws IOException {
179        }
180    }