001 /*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016 package org.opengion.hayabusa.servlet.multipart;
017
018 import java.io.FilterInputStream;
019 import java.io.IOException;
020 import javax.servlet.ServletInputStream;
021
022 /**
023 * ファイルア??ロード時のマルチパート???ファイル読取ストリー?す?
024 *
025 * @og.group そ?他機?
026 *
027 * @version 4.0
028 * @author Kazuhiko Hasegawa
029 * @since JDK5.0,
030 */
031 public class PartInputStream extends FilterInputStream {
032 private final String boundary;
033 private final byte [] buf = new byte[64*1024]; // 64k
034 private int count;
035 private int pos;
036 private boolean eof;
037
038 /**
039 * 読取ストリー?と区??を?してクラスを構築す?コンストラクター
040 *
041 * @param in ServletInputStreamオブジェク?
042 * @param boundary ???
043 * @throws IOException 上位?入出力エラー
044 */
045 PartInputStream( final ServletInputStream in, final String boundary) throws IOException {
046 super(in);
047 this.boundary = boundary;
048 }
049
050 /**
051 * ??タを埋めます?
052 *
053 * @throws IOException 入出力エラーが発生したと?
054 */
055 private void fill() throws IOException {
056 if(eof) {
057 return;
058 }
059 // as long as we are not just starting up
060 if(count > 0) {
061 // if the caller left the requisite amount spare in the buffer
062 if(count - pos == 2) {
063 // copy it back to the start of the buffer
064 System.arraycopy(buf, pos, buf, 0, count - pos);
065 count -= pos;
066 pos = 0;
067 } else {
068 // should never happen, but just in case
069 throw new IllegalStateException("fill() detected illegal buffer state");
070 }
071 }
072
073 // try and fill the entire buffer, starting at count, line by line
074 // but never read so close to the end that we might split a boundary
075 int read;
076 int maxRead = buf.length - boundary.length();
077 while (count < maxRead) {
078 // read a line
079 read = ((ServletInputStream)in).readLine(buf, count, buf.length - count);
080 // check for eof and boundary
081 if(read == -1) {
082 throw new IOException("unexpected end of part");
083 } else {
084 if(read >= boundary.length()) {
085 eof = true;
086 for(int i=0; i < boundary.length(); i++) {
087 if(boundary.charAt(i) != buf[count + i]) {
088 // Not the boundary!
089 eof = false;
090 break;
091 }
092 }
093 if(eof) {
094 break;
095 }
096 }
097 }
098 // success
099 count += read;
100 }
101 }
102
103 /**
104 * ??タを読み込みます?
105 *
106 * @return 読み取られた??タ
107 * @throws IOException 入出力エラーが発生したと?
108 */
109 @Override
110 public int read() throws IOException {
111 if(count - pos <= 2) {
112 fill();
113 if(count - pos <= 2) {
114 return -1;
115 }
116 }
117 return buf[pos++] & 0xff;
118 }
119
120 /**
121 * ??タを読み込みます?
122 *
123 * @param bt バイト??
124 *
125 * @return 読み取られた??タ
126 * @throws IOException 入出力エラーが発生したと?
127 */
128 @Override
129 public int read( final byte[] bt ) throws IOException {
130 return read(bt, 0, bt.length);
131 }
132
133 /**
134 * ??タを読み込みます?
135 *
136 * @param bt バイト??
137 * @param off 開始バイト数
138 * @param len 読み取りバイト数
139 *
140 * @return 読み取られた??タ
141 * @throws IOException 入出力エラーが発生したと?
142 */
143 @Override
144 public int read( final byte[] bt, final int off, final int len ) throws IOException {
145 int total = 0;
146 if(len == 0) {
147 return 0;
148 }
149
150 int avail = count - pos - 2;
151 if(avail <= 0) {
152 fill();
153 avail = count - pos - 2;
154 if(avail <= 0) {
155 return -1;
156 }
157 }
158 int copy = Math.min(len, avail);
159 System.arraycopy(buf, pos, bt, off, copy);
160 pos += copy;
161 total += copy;
162
163 while (total < len) {
164 fill();
165 avail = count - pos - 2;
166 if(avail <= 0) {
167 return total;
168 }
169 copy = Math.min(len - total, avail);
170 System.arraycopy(buf, pos, bt, off + total, copy);
171 pos += copy;
172 total += copy;
173 }
174 return total;
175 }
176
177 /**
178 * 利用可能かど?を返します?
179 *
180 * @return 利用可能かど?
181 * @throws IOException 入出力エラーが発生したと?
182 */
183 @Override
184 public int available() throws IOException {
185 int avail = (count - pos - 2) + in.available();
186 // Never return a negative value
187 return (avail < 0 ? 0 : avail);
188 }
189
190 /**
191 * 接続を閉じます?
192 *
193 * @throws IOException 入出力エラーが発生したと?
194 */
195 @Override
196 public void close() throws IOException {
197 if(!eof) {
198 int size = read(buf, 0, buf.length);
199 while( size != -1) {
200 size = read(buf, 0, buf.length);
201 }
202 }
203 }
204 }