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