View Javadoc
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  import org.apache.commons.io.IOUtils;
26  
27  /**
28   * Utility class for working with streams.
29   */
30  public final class Streams {
31  
32      /**
33       * Private constructor, to prevent instantiation.
34       * This class has only static methods.
35       */
36      private Streams() {
37          // Does nothing
38      }
39  
40      /**
41       * Default buffer size for use in
42       * {@link #copy(InputStream, OutputStream, boolean)}.
43       */
44      private static final int DEFAULT_BUFFER_SIZE = 8192;
45  
46      /**
47       * Copies the contents of the given {@link InputStream}
48       * to the given {@link OutputStream}. Shortcut for
49       * <pre>
50       *   copy(pInputStream, pOutputStream, new byte[8192]);
51       * </pre>
52       *
53       * @param inputStream The input stream, which is being read.
54       * It is guaranteed, that {@link InputStream#close()} is called
55       * on the stream.
56       * @param outputStream The output stream, to which data should
57       * be written. May be null, in which case the input streams
58       * contents are simply discarded.
59       * @param closeOutputStream True guarantees, that {@link OutputStream#close()}
60       * is called on the stream. False indicates, that only
61       * {@link OutputStream#flush()} should be called finally.
62       *
63       * @return Number of bytes, which have been copied.
64       * @throws IOException An I/O error occurred.
65       */
66      public static long copy(InputStream inputStream, OutputStream outputStream, boolean closeOutputStream)
67              throws IOException {
68          return copy(inputStream, outputStream, closeOutputStream, new byte[DEFAULT_BUFFER_SIZE]);
69      }
70  
71      /**
72       * Copies the contents of the given {@link InputStream}
73       * to the given {@link OutputStream}.
74       *
75       * @param inputStream The input stream, which is being read.
76       *   It is guaranteed, that {@link InputStream#close()} is called
77       *   on the stream.
78       * @param outputStream The output stream, to which data should
79       *   be written. May be null, in which case the input streams
80       *   contents are simply discarded.
81       * @param closeOutputStream True guarantees, that {@link OutputStream#close()}
82       *   is called on the stream. False indicates, that only
83       *   {@link OutputStream#flush()} should be called finally.
84       * @param buffer Temporary buffer, which is to be used for
85       *   copying data.
86       * @return Number of bytes, which have been copied.
87       * @throws IOException An I/O error occurred.
88       */
89      public static long copy(InputStream inputStream,
90              OutputStream outputStream, boolean closeOutputStream,
91              byte[] buffer)
92      throws IOException {
93          OutputStream out = outputStream;
94          InputStream in = inputStream;
95          try {
96              long total = 0;
97              for (;;) {
98                  int res = in.read(buffer);
99                  if (res == -1) {
100                     break;
101                 }
102                 if (res > 0) {
103                     total += res;
104                     if (out != null) {
105                         out.write(buffer, 0, res);
106                     }
107                 }
108             }
109             if (out != null) {
110                 if (closeOutputStream) {
111                     out.close();
112                 } else {
113                     out.flush();
114                 }
115                 out = null;
116             }
117             in.close();
118             in = null;
119             return total;
120         } finally {
121             IOUtils.closeQuietly(in);
122             if (closeOutputStream) {
123                 IOUtils.closeQuietly(out);
124             }
125         }
126     }
127 
128     /**
129      * This convenience method allows to read a
130      * {@link org.apache.commons.fileupload.FileItemStream}'s
131      * content into a string. The platform's default character encoding
132      * is used for converting bytes into characters.
133      *
134      * @param inputStream The input stream to read.
135      * @see #asString(InputStream, String)
136      * @return The streams contents, as a string.
137      * @throws IOException An I/O error occurred.
138      */
139     public static String asString(InputStream inputStream) throws IOException {
140         ByteArrayOutputStream baos = new ByteArrayOutputStream();
141         copy(inputStream, baos, true);
142         return baos.toString();
143     }
144 
145     /**
146      * This convenience method allows to read a
147      * {@link org.apache.commons.fileupload.FileItemStream}'s
148      * content into a string, using the given character encoding.
149      *
150      * @param inputStream The input stream to read.
151      * @param encoding The character encoding, typically "UTF-8".
152      * @see #asString(InputStream)
153      * @return The streams contents, as a string.
154      * @throws IOException An I/O error occurred.
155      */
156     public static String asString(InputStream inputStream, String encoding) throws IOException {
157         ByteArrayOutputStream baos = new ByteArrayOutputStream();
158         copy(inputStream, baos, true);
159         return baos.toString(encoding);
160     }
161 
162     /**
163      * Checks, whether the given file name is valid in the sense,
164      * that it doesn't contain any NUL characters. If the file name
165      * is valid, it will be returned without any modifications. Otherwise,
166      * an {@link InvalidFileNameException} is raised.
167      *
168      * @param fileName The file name to check
169      * @return Unmodified file name, if valid.
170      * @throws InvalidFileNameException The file name was found to be invalid.
171      */
172     public static String checkFileName(String fileName) {
173         if (fileName != null  &&  fileName.indexOf('\u0000') != -1) {
174             // pFileName.replace("\u0000", "\\0")
175             final StringBuilder sb = new StringBuilder();
176             for (int i = 0;  i < fileName.length();  i++) {
177                 char c = fileName.charAt(i);
178                 switch (c) {
179                     case 0:
180                         sb.append("\\0");
181                         break;
182                     default:
183                         sb.append(c);
184                         break;
185                 }
186             }
187             throw new InvalidFileNameException(fileName,
188                     "Invalid file name: " + sb);
189         }
190         return fileName;
191     }
192 
193 }