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 021package org.granite.gravity.tomcat; 022 023import java.io.IOException; 024import java.io.InputStream; 025 026/** 027 * An unsynchronized input/output byte buffer that avoids useless byte array copies. 028 * 029 * @author Franck 030 */ 031public 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}