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  
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 }