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 }