package net.i2p.data; /* * free (adj.): unencumbered; not under the control of others * Written by jrandom in 2003 and released into the public domain * with no warranty of any kind, either expressed or implied. * It probably won't make your computer catch on fire, or eat * your children, but it might. Use at your own risk. * */ import java.io.IOException; import java.io.InputStream; /** * Defines the hash as defined by the I2P data structure spec. * A hash is the SHA-256 of some data, taking up 32 bytes. * * @author jrandom */ public class Hash extends SimpleDataStructure { private volatile String _base64ed; private int _cachedHashCode; public final static int HASH_LENGTH = 32; public final static Hash FAKE_HASH = new Hash(new byte[HASH_LENGTH]); private static final int CACHE_SIZE = 2048; private static final SDSCache<Hash> _cache = new SDSCache<Hash>(Hash.class, HASH_LENGTH, CACHE_SIZE); /** * Pull from cache or return new * * WARNING - If the SDS is found in the cache, the passed-in * byte array will be returned to the SimpleByteCache for reuse. * Do NOT save a reference to the passed-in data, or use or modify it, * after this call. * * Ignore this warning and you WILL corrupt the cache or other data structures. * * @throws IllegalArgumentException if data is not the correct number of bytes * @since 0.8.3 */ public static Hash create(byte[] data) { return _cache.get(data); } /** * Pull from cache or return new * @throws ArrayIndexOutOfBoundsException if not enough bytes * @since 0.8.3 */ public static Hash create(byte[] data, int off) { return _cache.get(data, off); } /** * Pull from cache or return new * @since 0.8.3 */ public static Hash create(InputStream in) throws IOException { return _cache.get(in); } public Hash() { super(); } /** @throws IllegalArgumentException if data is not 32 bytes (null is ok) */ public Hash(byte data[]) { super(); setData(data); } public int length() { return HASH_LENGTH; } /** @throws IllegalArgumentException if data is not 32 bytes (null is ok) */ @Override public void setData(byte[] data) { super.setData(data); _base64ed = null; _cachedHashCode = super.hashCode(); } @Override public void readBytes(InputStream in) throws DataFormatException, IOException { super.readBytes(in); _base64ed = null; _cachedHashCode = super.hashCode(); } /** a Hash is a hash, so just use the first 4 bytes for speed */ @Override public int hashCode() { return _cachedHashCode; } @Override public String toBase64() { if (_base64ed == null) { _base64ed = super.toBase64(); } return _base64ed; } /** * For convenience. * @return "{52 chars}.b32.i2p" or null if data not set. * @since 0.9.25 */ public String toBase32() { if (_data == null) return null; return Base32.encode(_data) + ".b32.i2p"; } /** * @since 0.9.17 */ public static void clearCache() { _cache.clear(); } }