001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.fileupload.util;
018
019 import java.io.ByteArrayOutputStream;
020 import java.io.IOException;
021 import java.io.InputStream;
022 import java.io.OutputStream;
023
024 import org.apache.commons.fileupload.InvalidFileNameException;
025
026
027 /** Utility class for working with streams.
028 */
029 public final class Streams {
030 /**
031 * Private constructor, to prevent instantiation.
032 * This class has only static methods.
033 */
034 private Streams() {
035 // Does nothing
036 }
037
038 /**
039 * Default buffer size for use in
040 * {@link #copy(InputStream, OutputStream, boolean)}.
041 */
042 private static final int DEFAULT_BUFFER_SIZE = 8192;
043
044 /**
045 * Copies the contents of the given {@link InputStream}
046 * to the given {@link OutputStream}. Shortcut for
047 * <pre>
048 * copy(pInputStream, pOutputStream, new byte[8192]);
049 * </pre>
050 * @param pInputStream The input stream, which is being read.
051 * It is guaranteed, that {@link InputStream#close()} is called
052 * on the stream.
053 * @param pOutputStream The output stream, to which data should
054 * be written. May be null, in which case the input streams
055 * contents are simply discarded.
056 * @param pClose True guarantees, that {@link OutputStream#close()}
057 * is called on the stream. False indicates, that only
058 * {@link OutputStream#flush()} should be called finally.
059 *
060 * @return Number of bytes, which have been copied.
061 * @throws IOException An I/O error occurred.
062 */
063 public static long copy(InputStream pInputStream,
064 OutputStream pOutputStream, boolean pClose)
065 throws IOException {
066 return copy(pInputStream, pOutputStream, pClose,
067 new byte[DEFAULT_BUFFER_SIZE]);
068 }
069
070 /**
071 * Copies the contents of the given {@link InputStream}
072 * to the given {@link OutputStream}.
073 * @param pIn The input stream, which is being read.
074 * It is guaranteed, that {@link InputStream#close()} is called
075 * on the stream.
076 * @param pOut The output stream, to which data should
077 * be written. May be null, in which case the input streams
078 * contents are simply discarded.
079 * @param pClose True guarantees, that {@link OutputStream#close()}
080 * is called on the stream. False indicates, that only
081 * {@link OutputStream#flush()} should be called finally.
082 * @param pBuffer Temporary buffer, which is to be used for
083 * copying data.
084 * @return Number of bytes, which have been copied.
085 * @throws IOException An I/O error occurred.
086 */
087 public static long copy(InputStream pIn,
088 OutputStream pOut, boolean pClose,
089 byte[] pBuffer)
090 throws IOException {
091 OutputStream out = pOut;
092 InputStream in = pIn;
093 try {
094 long total = 0;
095 for (;;) {
096 int res = in.read(pBuffer);
097 if (res == -1) {
098 break;
099 }
100 if (res > 0) {
101 total += res;
102 if (out != null) {
103 out.write(pBuffer, 0, res);
104 }
105 }
106 }
107 if (out != null) {
108 if (pClose) {
109 out.close();
110 } else {
111 out.flush();
112 }
113 out = null;
114 }
115 in.close();
116 in = null;
117 return total;
118 } finally {
119 if (in != null) {
120 try {
121 in.close();
122 } catch (Throwable t) {
123 /* Ignore me */
124 }
125 }
126 if (pClose && out != null) {
127 try {
128 out.close();
129 } catch (Throwable t) {
130 /* Ignore me */
131 }
132 }
133 }
134 }
135
136 /**
137 * This convenience method allows to read a
138 * {@link org.apache.commons.fileupload.FileItemStream}'s
139 * content into a string. The platform's default character encoding
140 * is used for converting bytes into characters.
141 * @param pStream The input stream to read.
142 * @see #asString(InputStream, String)
143 * @return The streams contents, as a string.
144 * @throws IOException An I/O error occurred.
145 */
146 public static String asString(InputStream pStream) throws IOException {
147 ByteArrayOutputStream baos = new ByteArrayOutputStream();
148 copy(pStream, baos, true);
149 return baos.toString();
150 }
151
152 /**
153 * This convenience method allows to read a
154 * {@link org.apache.commons.fileupload.FileItemStream}'s
155 * content into a string, using the given character encoding.
156 * @param pStream The input stream to read.
157 * @param pEncoding The character encoding, typically "UTF-8".
158 * @see #asString(InputStream)
159 * @return The streams contents, as a string.
160 * @throws IOException An I/O error occurred.
161 */
162 public static String asString(InputStream pStream, String pEncoding)
163 throws IOException {
164 ByteArrayOutputStream baos = new ByteArrayOutputStream();
165 copy(pStream, baos, true);
166 return baos.toString(pEncoding);
167 }
168
169 /**
170 * Checks, whether the given file name is valid in the sense,
171 * that it doesn't contain any NUL characters. If the file name
172 * is valid, it will be returned without any modifications. Otherwise,
173 * an {@link InvalidFileNameException} is raised.
174 * @param pFileName The file name to check
175 * @return Unmodified file name, if valid.
176 * @throws InvalidFileNameException The file name was found to be invalid.
177 */
178 public static String checkFileName(String pFileName) {
179 if (pFileName != null && pFileName.indexOf('\u0000') != -1) {
180 // pFileName.replace("\u0000", "\\0")
181 final StringBuffer sb = new StringBuffer();
182 for (int i = 0; i < pFileName.length(); i++) {
183 char c = pFileName.charAt(i);
184 switch (c) {
185 case 0:
186 sb.append("\\0");
187 break;
188 default:
189 sb.append(c);
190 break;
191 }
192 }
193 throw new InvalidFileNameException(pFileName,
194 "Invalid file name: " + sb);
195 }
196 return pFileName;
197 }
198 }