package com.limegroup.gnutella.util;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import com.limegroup.gnutella.MessageService;
import com.limegroup.gnutella.ErrorService;
/**
* Provides utility I/O methods, used by multiple classes
* @author Anurag Singla
*/
public class IOUtils {
/**
* Attempts to handle an IOException. If we know expect the problem,
* we can either ignore it or display a friendly error (both returning
* true, for handled) or expect the outer-world to handle it (and
* return false).
*
* If friendly is null, a generic error related to the bug is displayed.
*
* @return true if we could handle the error.
*/
public static boolean handleException(IOException ioe, String friendly) {
if(friendly == null)
friendly = "GENERIC";
return handle(ioe, friendly);
}
/**
* Looks through every cause of an Exception to see if we know how
* to handle it.
*/
private static boolean handle(Throwable e, String friendly) {
while(e != null) {
String msg = e.getMessage();
if(msg != null) {
msg = msg.toLowerCase();
// If the user's disk is full, let them know.
if(StringUtils.contains(msg, "no space left") ||
StringUtils.contains(msg, "not enough space")) {
MessageService.showError("ERROR_DISK_FULL_" + friendly);
return true;
}
// If the file is locked, let them know.
if(StringUtils.contains(msg, "being used by another process")) {
MessageService.showError("ERROR_LOCKED_BY_PROCESS_" + friendly);
return true;
}
// If we don't have permissions to write, let them know.
if(StringUtils.contains(msg, "access is denied") ||
StringUtils.contains(msg, "permission denied") ) {
MessageService.showError("ERROR_ACCESS_DENIED_" + friendly);
return true;
}
if(StringUtils.contains(msg, "invalid argument")) {
MessageService.showError("ERROR_INVALID_NAME_" + friendly);
return true;
}
}
e = e.getCause();
}
// dunno what to do, let the outer world handle it.
return false;
}
/**
* Returns the first word of specified maximum size up to the first space
* and returns it. This does not read up to the first whitespace
* character -- it only looks for a single space. This is particularly
* useful for reading HTTP requests, as the request method, the URI, and
* the HTTP version must all be separated by a single space.
* Note that only one extra character is read from the stream in the case of
* success (the white space character after the word).
*
* @param in The input stream from where to read the word
* @param maxSize The maximum size of the word.
* @return the first word (i.e., no whitespace) of specified maximum size
* @exception IOException if the word of specified maxSize couldnt be read,
* either due to stream errors, or timeouts
*/
public static String readWord(InputStream in, int maxSize)
throws IOException {
final char[] buf = new char[maxSize];
int i = 0;
//iterate till maxSize + 1 (for white space)
while (true) {
int got;
try {
got = in.read();
if (got >= 0) { // not EOF
if ((char)got != ' ') { //didn't get word. Exclude space.
if (i < maxSize) { //We dont store the last letter
buf[i++] = (char)got;
continue;
}
//if word of size upto maxsize not found, throw an
//IOException. (Fixes bug 26 in 'core' project)
throw new IOException("could not read word");
}
return new String(buf, 0, i);
}
throw new IOException("unexpected end of file");
} catch (ArrayIndexOutOfBoundsException aioobe) {
// thrown in strange circumstances of in.read(), consider IOX.
throw new IOException("unexpected aioobe");
}
}
}
/**
* Reads a word, but if the connection closes, returns the largest word read
* instead of throwing an IOX.
*/
public static String readLargestWord(InputStream in, int maxSize)
throws IOException {
final char[] buf = new char[maxSize];
int i = 0;
//iterate till maxSize + 1 (for white space)
while (true) {
int got;
try {
got = in.read();
if(got == -1) {
if(i == 0)
throw new IOException("could not read any word.");
else
return new String(buf, 0, i);
} else if (got >= 0) {
if ((char)got != ' ') { //didn't get word. Exclude space.
if (i < maxSize) { //We dont store the last letter
buf[i++] = (char)got;
continue;
}
//if word of size upto maxsize not found, throw an
//IOException. (Fixes bug 26 in 'core' project)
throw new IOException("could not read word");
}
return new String(buf, 0, i);
}
throw new IOException("unknown got amount");
} catch (ArrayIndexOutOfBoundsException aioobe) {
// thrown in strange circumstances of in.read(), consider IOX.
throw new IOException("unexpected aioobe");
}
}
}
public static long ensureSkip(InputStream in, long length) throws IOException {
long skipped = 0;
while(skipped < length) {
long current = in.skip(length - skipped);
if(current == -1 || current == 0)
throw new EOFException("eof");
else
skipped += current;
}
return skipped;
}
public static void close(InputStream in) {
if(in != null) {
try {
in.close();
} catch(IOException ignored) {}
}
}
public static void close(OutputStream out) {
if(out != null) {
try {
out.close();
} catch(IOException ignored) {}
}
}
public static void close(RandomAccessFile raf) {
if(raf != null) {
try {
raf.close();
} catch(IOException ignored) {}
}
}
public static void close(Socket s) {
if(s != null) {
try {
close(s.getInputStream());
} catch(IOException ignored) {}
try {
close(s.getOutputStream());
} catch(IOException ignored) {}
try {
s.close();
} catch(IOException ignored) {}
}
}
public static void close(ServerSocket s) {
if(s != null) {
try {
s.close();
} catch(IOException ignored) {}
}
}
/**
* Deflates (compresses) the data.
*/
public static byte[] deflate(byte[] data) {
OutputStream dos = null;
try {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
dos = new DeflaterOutputStream(baos);
dos.write(data, 0, data.length);
dos.close(); //flushes bytes
return baos.toByteArray();
} catch(IOException impossible) {
ErrorService.error(impossible);
return null;
} finally {
IOUtils.close(dos);
}
}
/**
* Inflates (uncompresses) the data.
*/
public static byte[] inflate(byte[] data) throws IOException {
InputStream in = null;
try {
in = new InflaterInputStream(new ByteArrayInputStream(data));
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[64];
while(true) {
int read = in.read(buf, 0, buf.length);
if(read == -1)
break;
out.write(buf, 0, read);
}
return out.toByteArray();
} catch(OutOfMemoryError oome) {
throw new IOException(oome.getMessage());
} finally {
IOUtils.close(in);
}
}
}