package net.lax1dude.eaglercraft.sp; public class EaglerUUID { private final long mostSigBits; private final long leastSigBits; private EaglerUUID(byte[] data) { long msb = 0; long lsb = 0; assert data.length == 16 : "data must be 16 bytes in length"; for (int i = 0; i < 8; i++) msb = (msb << 8) | (data[i] & 0xff); for (int i = 8; i < 16; i++) lsb = (lsb << 8) | (data[i] & 0xff); this.mostSigBits = msb; this.leastSigBits = lsb; } public EaglerUUID(long mostSigBits, long leastSigBits) { this.mostSigBits = mostSigBits; this.leastSigBits = leastSigBits; } private static final EaglercraftRandom random = new EaglercraftRandom(); public static EaglerUUID randomUUID() { byte[] randomBytes = new byte[16]; random.nextBytes(randomBytes); randomBytes[6] &= 0x0f; /* clear version */ randomBytes[6] |= 0x40; /* set to version 4 */ randomBytes[8] &= 0x3f; /* clear variant */ randomBytes[8] |= 0x80; /* set to IETF variant */ return new EaglerUUID(randomBytes); } private static final MD5Digest yee = new MD5Digest(); public static EaglerUUID nameUUIDFromBytes(byte[] name) { yee.update(name, 0, name.length); byte[] md5Bytes = new byte[16]; yee.doFinal(md5Bytes, 0); md5Bytes[6] &= 0x0f; /* clear version */ md5Bytes[6] |= 0x30; /* set to version 3 */ md5Bytes[8] &= 0x3f; /* clear variant */ md5Bytes[8] |= 0x80; /* set to IETF variant */ return new EaglerUUID(md5Bytes); } public static EaglerUUID fromString(String name) { String[] components = name.split("-"); if (components.length != 5) throw new IllegalArgumentException("Invalid UUID string: " + name); for (int i = 0; i < 5; i++) components[i] = "0x" + components[i]; long mostSigBits = Long.decode(components[0]).longValue(); mostSigBits <<= 16; mostSigBits |= Long.decode(components[1]).longValue(); mostSigBits <<= 16; mostSigBits |= Long.decode(components[2]).longValue(); long leastSigBits = Long.decode(components[3]).longValue(); leastSigBits <<= 48; leastSigBits |= Long.decode(components[4]).longValue(); return new EaglerUUID(mostSigBits, leastSigBits); } public long getLeastSignificantBits() { return leastSigBits; } public long getMostSignificantBits() { return mostSigBits; } /** * The version number associated with this {@code UUID}. The version * number describes how this {@code UUID} was generated. *
* The version number has the following meaning: *
* The variant number has the following meaning: *
The 14 bit clock sequence value is constructed from the clock * sequence field of this UUID. The clock sequence field is used to * guarantee temporal uniqueness in a time-based UUID. * *
The {@code clockSequence} value is only meaningful in a time-based * UUID, which has version type 1. If this UUID is not a time-based UUID * then this method throws UnsupportedOperationException. * * @return The clock sequence of this {@code UUID} * @throws UnsupportedOperationException If this UUID is not a version 1 UUID */ public int clockSequence() { if (version() != 1) { throw new UnsupportedOperationException("Not a time-based UUID"); } return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48); } public String toString() { return (digits(mostSigBits >> 32, 8) + "-" + digits(mostSigBits >> 16, 4) + "-" + digits(mostSigBits, 4) + "-" + digits(leastSigBits >> 48, 4) + "-" + digits(leastSigBits, 12)); } private static String digits(long val, int digits) { long hi = 1L << (digits * 4); return Long.toHexString(hi | (val & (hi - 1))).substring(1); } public int hashCode() { long hilo = mostSigBits ^ leastSigBits; return ((int) (hilo >> 32)) ^ (int) hilo; } public boolean equals(Object obj) { if ((null == obj) || !(obj instanceof EaglerUUID)) return false; EaglerUUID id = (EaglerUUID) obj; return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits); } public int compareTo(EaglerUUID val) { return (this.mostSigBits < val.mostSigBits ? -1 : (this.mostSigBits > val.mostSigBits ? 1 : (this.leastSigBits < val.leastSigBits ? -1 : (this.leastSigBits > val.leastSigBits ? 1 : 0)))); } }