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