1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.fileupload.util;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23
24 import org.apache.commons.fileupload.InvalidFileNameException;
25
26
27 /** Utility class for working with streams.
28 */
29 public final class Streams {
30 /**
31 * Private constructor, to prevent instantiation.
32 * This class has only static methods.
33 */
34 private Streams() {
35 // Does nothing
36 }
37
38 /**
39 * Default buffer size for use in
40 * {@link #copy(InputStream, OutputStream, boolean)}.
41 */
42 private static final int DEFAULT_BUFFER_SIZE = 8192;
43
44 /**
45 * Copies the contents of the given {@link InputStream}
46 * to the given {@link OutputStream}. Shortcut for
47 * <pre>
48 * copy(pInputStream, pOutputStream, new byte[8192]);
49 * </pre>
50 * @param pInputStream The input stream, which is being read.
51 * It is guaranteed, that {@link InputStream#close()} is called
52 * on the stream.
53 * @param pOutputStream The output stream, to which data should
54 * be written. May be null, in which case the input streams
55 * contents are simply discarded.
56 * @param pClose True guarantees, that {@link OutputStream#close()}
57 * is called on the stream. False indicates, that only
58 * {@link OutputStream#flush()} should be called finally.
59 *
60 * @return Number of bytes, which have been copied.
61 * @throws IOException An I/O error occurred.
62 */
63 public static long copy(InputStream pInputStream,
64 OutputStream pOutputStream, boolean pClose)
65 throws IOException {
66 return copy(pInputStream, pOutputStream, pClose,
67 new byte[DEFAULT_BUFFER_SIZE]);
68 }
69
70 /**
71 * Copies the contents of the given {@link InputStream}
72 * to the given {@link OutputStream}.
73 * @param pIn The input stream, which is being read.
74 * It is guaranteed, that {@link InputStream#close()} is called
75 * on the stream.
76 * @param pOut The output stream, to which data should
77 * be written. May be null, in which case the input streams
78 * contents are simply discarded.
79 * @param pClose True guarantees, that {@link OutputStream#close()}
80 * is called on the stream. False indicates, that only
81 * {@link OutputStream#flush()} should be called finally.
82 * @param pBuffer Temporary buffer, which is to be used for
83 * copying data.
84 * @return Number of bytes, which have been copied.
85 * @throws IOException An I/O error occurred.
86 */
87 public static long copy(InputStream pIn,
88 OutputStream pOut, boolean pClose,
89 byte[] pBuffer)
90 throws IOException {
91 OutputStream out = pOut;
92 InputStream in = pIn;
93 try {
94 long total = 0;
95 for (;;) {
96 int res = in.read(pBuffer);
97 if (res == -1) {
98 break;
99 }
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 }