package com.indyforge.twod.engine.io; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.security.MessageDigest; /** * Provides some simple I/O routines. * * @author Christopher Probst * @author Matthias Hesse */ public final class IoRoutines { /* * Used for faster byte to hex conversion. */ private static final String HEX_RANGE = "0123456789ABCDEF"; /** * This method reads the complete input stream and stores the data in an * array. * * @param inputStream * The input stream you want to read completely. * @return an array which contains the binary data. * @throws IOException * If an I/O exception occurs. */ public static byte[] readFully(InputStream inputStream) throws IOException { if (inputStream == null) { throw new NullPointerException("inputStream"); } ByteArrayOutputStream array = new ByteArrayOutputStream(); byte[] buffer = new byte[0xFFFF]; int read; while ((read = inputStream.read(buffer)) != -1) { array.write(buffer, 0, read); } return array.toByteArray(); } /** * Simple method to convert binary data to hex. * * @param data * The binary data you want to represent as hex. * @return the hex string. */ public static String toHex(byte[] data) { if (data == null) { throw new NullPointerException("data"); } // Use a fast string builder for this purpose StringBuilder stringBuilder = new StringBuilder(2 * data.length); // Iterate over all bytes for (byte b : data) { // Bit shifting and &-operator do all the magic here... stringBuilder.append(HEX_RANGE.charAt((b & 0xF0) >> 4)).append( HEX_RANGE.charAt((b & 0x0F))); } // Represent the final string return stringBuilder.toString(); } /** * Calculates the string hash for a given input stream. * * @param inputStream * The input stream. * @return the hex string. * @throws Exception * If an exception occurs. */ public static String calcHexHash(InputStream inputStream) throws Exception { return toHex(calcHash(inputStream)); } /** * Calculates the binary hash for a given input stream. * * @param inputStream * The input stream. * @return the binary hash. * @throws Exception * If an exception occurs. */ public static byte[] calcHash(InputStream inputStream) throws Exception { if (inputStream == null) { throw new NullPointerException("inputStream"); } try { // Use SHA-1 for hashing MessageDigest digest = MessageDigest.getInstance("SHA-1"); // 0xFFFF should increase calculation byte[] buffer = new byte[0xFFFF]; // Tmp int read; // Read & update as long there are remaining bytes while ((read = inputStream.read(buffer)) != -1) { digest.update(buffer, 0, read); } // Return the hash return digest.digest(); } finally { inputStream.close(); } } /** * Serializes the given object. * * @param object * The object you want to serialize. * @return an array which contains the binary data. * @throws IOException * If an I/O exception occurs. */ public static byte[] serialize(Object object) throws IOException { ByteArrayOutputStream array = new ByteArrayOutputStream(); ObjectOutputStream objectOutput = new ObjectOutputStream(array); objectOutput.writeObject(object); objectOutput.flush(); objectOutput.close(); return array.toByteArray(); } /** * Deserializes the given array. * * @param data * The binary data you want to deserialize. You should use * {@link IoRoutines#serialize(Object)} to get such an array. * @return the deserialized object. * @throws IOException * If an I/O exception occurs. * @throws ClassNotFoundException * If a class could not be loaded. */ public static Object deserialize(byte[] data) throws IOException, ClassNotFoundException { return new ObjectInputStream(new ByteArrayInputStream(data)) .readObject(); } // Should not be instantiated private IoRoutines() { } }