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             */
044            PartInputStream( final ServletInputStream in,
045                                            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    }