001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.fileupload.util; 018 019import java.io.ByteArrayOutputStream; 020import java.io.IOException; 021import java.io.InputStream; 022import java.io.OutputStream; 023 024import org.apache.commons.fileupload.InvalidFileNameException; 025import org.apache.commons.io.IOUtils; 026 027/** 028 * Utility class for working with streams. 029 */ 030public final class Streams { 031 032 /** 033 * Private constructor, to prevent instantiation. 034 * This class has only static methods. 035 */ 036 private Streams() { 037 // Does nothing 038 } 039 040 /** 041 * Default buffer size for use in 042 * {@link #copy(InputStream, OutputStream, boolean)}. 043 */ 044 public static final int DEFAULT_BUFFER_SIZE = 8192; 045 046 /** 047 * Copies the contents of the given {@link InputStream} 048 * to the given {@link OutputStream}. Shortcut for 049 * <pre> 050 * copy(pInputStream, pOutputStream, new byte[8192]); 051 * </pre> 052 * 053 * @param inputStream The input stream, which is being read. 054 * It is guaranteed, that {@link InputStream#close()} is called 055 * on the stream. 056 * @param outputStream The output stream, to which data should 057 * be written. May be null, in which case the input streams 058 * contents are simply discarded. 059 * @param closeOutputStream True guarantees, that {@link OutputStream#close()} 060 * is called on the stream. False indicates, that only 061 * {@link OutputStream#flush()} should be called finally. 062 * 063 * @return Number of bytes, which have been copied. 064 * @throws IOException An I/O error occurred. 065 */ 066 public static long copy(InputStream inputStream, OutputStream outputStream, boolean closeOutputStream) 067 throws IOException { 068 return copy(inputStream, outputStream, closeOutputStream, new byte[DEFAULT_BUFFER_SIZE]); 069 } 070 071 /** 072 * Copies the contents of the given {@link InputStream} 073 * to the given {@link OutputStream}. 074 * 075 * @param inputStream The input stream, which is being read. 076 * It is guaranteed, that {@link InputStream#close()} is called 077 * on the stream. 078 * @param outputStream The output stream, to which data should 079 * be written. May be null, in which case the input streams 080 * contents are simply discarded. 081 * @param closeOutputStream True guarantees, that {@link OutputStream#close()} 082 * is called on the stream. False indicates, that only 083 * {@link OutputStream#flush()} should be called finally. 084 * @param buffer Temporary buffer, which is to be used for 085 * copying data. 086 * @return Number of bytes, which have been copied. 087 * @throws IOException An I/O error occurred. 088 */ 089 public static long copy(InputStream inputStream, 090 OutputStream outputStream, boolean closeOutputStream, 091 byte[] buffer) 092 throws IOException { 093 OutputStream out = outputStream; 094 InputStream in = inputStream; 095 try { 096 long total = 0; 097 for (;;) { 098 int res = in.read(buffer); 099 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}