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 * 030 * @version $Id: Streams.java 1565332 2014-02-06 16:42:19Z ggregory $ 031 */ 032public final class Streams { 033 034 /** 035 * Private constructor, to prevent instantiation. 036 * This class has only static methods. 037 */ 038 private Streams() { 039 // Does nothing 040 } 041 042 /** 043 * Default buffer size for use in 044 * {@link #copy(InputStream, OutputStream, boolean)}. 045 */ 046 private static final int DEFAULT_BUFFER_SIZE = 8192; 047 048 /** 049 * Copies the contents of the given {@link InputStream} 050 * to the given {@link OutputStream}. Shortcut for 051 * <pre> 052 * copy(pInputStream, pOutputStream, new byte[8192]); 053 * </pre> 054 * 055 * @param inputStream The input stream, which is being read. 056 * It is guaranteed, that {@link InputStream#close()} is called 057 * on the stream. 058 * @param outputStream The output stream, to which data should 059 * be written. May be null, in which case the input streams 060 * contents are simply discarded. 061 * @param closeOutputStream True guarantees, that {@link OutputStream#close()} 062 * is called on the stream. False indicates, that only 063 * {@link OutputStream#flush()} should be called finally. 064 * 065 * @return Number of bytes, which have been copied. 066 * @throws IOException An I/O error occurred. 067 */ 068 public static long copy(InputStream inputStream, OutputStream outputStream, boolean closeOutputStream) 069 throws IOException { 070 return copy(inputStream, outputStream, closeOutputStream, new byte[DEFAULT_BUFFER_SIZE]); 071 } 072 073 /** 074 * Copies the contents of the given {@link InputStream} 075 * to the given {@link OutputStream}. 076 * 077 * @param inputStream The input stream, which is being read. 078 * It is guaranteed, that {@link InputStream#close()} is called 079 * on the stream. 080 * @param outputStream The output stream, to which data should 081 * be written. May be null, in which case the input streams 082 * contents are simply discarded. 083 * @param closeOutputStream True guarantees, that {@link OutputStream#close()} 084 * is called on the stream. False indicates, that only 085 * {@link OutputStream#flush()} should be called finally. 086 * @param buffer Temporary buffer, which is to be used for 087 * copying data. 088 * @return Number of bytes, which have been copied. 089 * @throws IOException An I/O error occurred. 090 */ 091 public static long copy(InputStream inputStream, 092 OutputStream outputStream, boolean closeOutputStream, 093 byte[] buffer) 094 throws IOException { 095 OutputStream out = outputStream; 096 InputStream in = inputStream; 097 try { 098 long total = 0; 099 for (;;) { 100 int res = in.read(buffer); 101 if (res == -1) { 102 break; 103 } 104 if (res > 0) { 105 total += res; 106 if (out != null) { 107 out.write(buffer, 0, res); 108 } 109 } 110 } 111 if (out != null) { 112 if (closeOutputStream) { 113 out.close(); 114 } else { 115 out.flush(); 116 } 117 out = null; 118 } 119 in.close(); 120 in = null; 121 return total; 122 } finally { 123 IOUtils.closeQuietly(in); 124 if (closeOutputStream) { 125 IOUtils.closeQuietly(out); 126 } 127 } 128 } 129 130 /** 131 * This convenience method allows to read a 132 * {@link org.apache.commons.fileupload.FileItemStream}'s 133 * content into a string. The platform's default character encoding 134 * is used for converting bytes into characters. 135 * 136 * @param inputStream The input stream to read. 137 * @see #asString(InputStream, String) 138 * @return The streams contents, as a string. 139 * @throws IOException An I/O error occurred. 140 */ 141 public static String asString(InputStream inputStream) throws IOException { 142 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 143 copy(inputStream, baos, true); 144 return baos.toString(); 145 } 146 147 /** 148 * This convenience method allows to read a 149 * {@link org.apache.commons.fileupload.FileItemStream}'s 150 * content into a string, using the given character encoding. 151 * 152 * @param inputStream The input stream to read. 153 * @param encoding The character encoding, typically "UTF-8". 154 * @see #asString(InputStream) 155 * @return The streams contents, as a string. 156 * @throws IOException An I/O error occurred. 157 */ 158 public static String asString(InputStream inputStream, String encoding) throws IOException { 159 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 160 copy(inputStream, baos, true); 161 return baos.toString(encoding); 162 } 163 164 /** 165 * Checks, whether the given file name is valid in the sense, 166 * that it doesn't contain any NUL characters. If the file name 167 * is valid, it will be returned without any modifications. Otherwise, 168 * an {@link InvalidFileNameException} is raised. 169 * 170 * @param fileName The file name to check 171 * @return Unmodified file name, if valid. 172 * @throws InvalidFileNameException The file name was found to be invalid. 173 */ 174 public static String checkFileName(String fileName) { 175 if (fileName != null && fileName.indexOf('\u0000') != -1) { 176 // pFileName.replace("\u0000", "\\0") 177 final StringBuilder sb = new StringBuilder(); 178 for (int i = 0; i < fileName.length(); i++) { 179 char c = fileName.charAt(i); 180 switch (c) { 181 case 0: 182 sb.append("\\0"); 183 break; 184 default: 185 sb.append(c); 186 break; 187 } 188 } 189 throw new InvalidFileNameException(fileName, 190 "Invalid file name: " + sb); 191 } 192 return fileName; 193 } 194 195}