mirror of
http://git.eaglercraft.rip/eaglercraft/eaglercraft-1.8.git
synced 2025-04-29 01:51:58 -05:00
254 lines
7.1 KiB
Java
254 lines
7.1 KiB
Java
package net.lax1dude.eaglercraft.v1_8;
|
|
|
|
import net.lax1dude.eaglercraft.v1_8.crypto.MD5Digest;
|
|
|
|
/**
|
|
* Copyright (c) 2022 lax1dude. All Rights Reserved.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
public class EaglercraftUUID implements Comparable<EaglercraftUUID> {
|
|
|
|
public final long msb;
|
|
public final long lsb;
|
|
private int hash = 0;
|
|
private boolean hasHash;
|
|
|
|
public EaglercraftUUID(long msb, long lsb) {
|
|
this.msb = msb;
|
|
this.lsb = lsb;
|
|
}
|
|
|
|
public EaglercraftUUID(byte[] uuid) {
|
|
long msb = 0;
|
|
long lsb = 0;
|
|
for (int i = 0; i < 8; i++)
|
|
msb = (msb << 8) | (uuid[i] & 0xff);
|
|
for (int i = 8; i < 16; i++)
|
|
lsb = (lsb << 8) | (uuid[i] & 0xff);
|
|
this.msb = msb;
|
|
this.lsb = lsb;
|
|
}
|
|
|
|
public EaglercraftUUID(String uuid) {
|
|
String[] components = uuid.split("-");
|
|
if (components.length != 5)
|
|
throw new IllegalArgumentException("Invalid UUID string: " + uuid);
|
|
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();
|
|
|
|
this.msb = mostSigBits;
|
|
this.lsb = leastSigBits;
|
|
}
|
|
|
|
private static byte long7(long x) {
|
|
return (byte) (x >> 56);
|
|
}
|
|
|
|
private static byte long6(long x) {
|
|
return (byte) (x >> 48);
|
|
}
|
|
|
|
private static byte long5(long x) {
|
|
return (byte) (x >> 40);
|
|
}
|
|
|
|
private static byte long4(long x) {
|
|
return (byte) (x >> 32);
|
|
}
|
|
|
|
private static byte long3(long x) {
|
|
return (byte) (x >> 24);
|
|
}
|
|
|
|
private static byte long2(long x) {
|
|
return (byte) (x >> 16);
|
|
}
|
|
|
|
private static byte long1(long x) {
|
|
return (byte) (x >> 8);
|
|
}
|
|
|
|
private static byte long0(long x) {
|
|
return (byte) (x);
|
|
}
|
|
|
|
public byte[] getBytes() {
|
|
byte[] ret = new byte[16];
|
|
ret[0] = long7(msb);
|
|
ret[1] = long6(msb);
|
|
ret[2] = long5(msb);
|
|
ret[3] = long4(msb);
|
|
ret[4] = long3(msb);
|
|
ret[5] = long2(msb);
|
|
ret[6] = long1(msb);
|
|
ret[7] = long0(msb);
|
|
ret[8] = long7(lsb);
|
|
ret[9] = long6(lsb);
|
|
ret[10] = long5(lsb);
|
|
ret[11] = long4(lsb);
|
|
ret[12] = long3(lsb);
|
|
ret[13] = long2(lsb);
|
|
ret[14] = long1(lsb);
|
|
ret[15] = long0(lsb);
|
|
return ret;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return (digits(msb >> 32, 8) + "-" + digits(msb >> 16, 4) + "-" + digits(msb, 4) + "-" + digits(lsb >> 48, 4)
|
|
+ "-" + digits(lsb, 12));
|
|
}
|
|
|
|
private static String digits(long val, int digits) {
|
|
long hi = 1L << (digits * 4);
|
|
return Long.toHexString(hi | (val & (hi - 1))).substring(1);
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
if(hash == 0 && !hasHash) {
|
|
long hilo = msb ^ lsb;
|
|
hash = ((int) (hilo >> 32)) ^ (int) hilo;
|
|
hasHash = true;
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object o) {
|
|
if(!(o instanceof EaglercraftUUID)) return false;
|
|
EaglercraftUUID oo = (EaglercraftUUID)o;
|
|
return (hasHash && oo.hasHash)
|
|
? (hash == oo.hash && msb == oo.msb && lsb == oo.lsb)
|
|
: (msb == oo.msb && lsb == oo.lsb);
|
|
}
|
|
|
|
public long getMostSignificantBits() {
|
|
return msb;
|
|
}
|
|
|
|
public long getLeastSignificantBits() {
|
|
return lsb;
|
|
}
|
|
|
|
private static final String HEX = "0123456789ABCDEF";
|
|
|
|
private static int nibbleValue(char c) {
|
|
int v = HEX.indexOf(Character.toUpperCase(c));
|
|
if (v == -1) {
|
|
return 0;
|
|
} else {
|
|
return v;
|
|
}
|
|
}
|
|
|
|
private static long parse4Nibbles(String name, int pos) {
|
|
int ch1 = nibbleValue(name.charAt(pos));
|
|
int ch2 = nibbleValue(name.charAt(pos + 1));
|
|
int ch3 = nibbleValue(name.charAt(pos + 2));
|
|
int ch4 = nibbleValue(name.charAt(pos + 3));
|
|
return (ch1 << 12) | (ch2 << 8) | (ch3 << 4) | ch4;
|
|
}
|
|
|
|
public static EaglercraftUUID fromString(String name) {
|
|
if (name.length() == 36) {
|
|
char ch1 = name.charAt(8);
|
|
char ch2 = name.charAt(13);
|
|
char ch3 = name.charAt(18);
|
|
char ch4 = name.charAt(23);
|
|
if (ch1 == '-' && ch2 == '-' && ch3 == '-' && ch4 == '-') {
|
|
long msb1 = parse4Nibbles(name, 0);
|
|
long msb2 = parse4Nibbles(name, 4);
|
|
long msb3 = parse4Nibbles(name, 9);
|
|
long msb4 = parse4Nibbles(name, 14);
|
|
long lsb1 = parse4Nibbles(name, 19);
|
|
long lsb2 = parse4Nibbles(name, 24);
|
|
long lsb3 = parse4Nibbles(name, 28);
|
|
long lsb4 = parse4Nibbles(name, 32);
|
|
if ((msb1 | msb2 | msb3 | msb4 | lsb1 | lsb2 | lsb3 | lsb4) >= 0) {
|
|
return new EaglercraftUUID(msb1 << 48 | msb2 << 32 | msb3 << 16 | msb4,
|
|
lsb1 << 48 | lsb2 << 32 | lsb3 << 16 | lsb4);
|
|
}
|
|
}
|
|
}
|
|
return fromString1(name);
|
|
}
|
|
|
|
private static EaglercraftUUID fromString1(String name) {
|
|
int len = name.length();
|
|
if (len > 36) {
|
|
throw new IllegalArgumentException("UUID string too large");
|
|
}
|
|
|
|
int dash1 = name.indexOf('-', 0);
|
|
int dash2 = name.indexOf('-', dash1 + 1);
|
|
int dash3 = name.indexOf('-', dash2 + 1);
|
|
int dash4 = name.indexOf('-', dash3 + 1);
|
|
int dash5 = name.indexOf('-', dash4 + 1);
|
|
|
|
if (dash4 < 0 || dash5 >= 0) {
|
|
throw new IllegalArgumentException("Invalid UUID string: " + name);
|
|
}
|
|
|
|
long mostSigBits = JDKBackports.parseLong(name, 0, dash1, 16) & 0xffffffffL;
|
|
mostSigBits <<= 16;
|
|
mostSigBits |= JDKBackports.parseLong(name, dash1 + 1, dash2, 16) & 0xffffL;
|
|
mostSigBits <<= 16;
|
|
mostSigBits |= JDKBackports.parseLong(name, dash2 + 1, dash3, 16) & 0xffffL;
|
|
long leastSigBits = JDKBackports.parseLong(name, dash3 + 1, dash4, 16) & 0xffffL;
|
|
leastSigBits <<= 48;
|
|
leastSigBits |= JDKBackports.parseLong(name, dash4 + 1, len, 16) & 0xffffffffffffL;
|
|
|
|
return new EaglercraftUUID(mostSigBits, leastSigBits);
|
|
}
|
|
|
|
public static EaglercraftUUID nameUUIDFromBytes(byte[] bytes) {
|
|
MD5Digest dg = new MD5Digest();
|
|
dg.update(bytes, 0, bytes.length);
|
|
byte[] md5Bytes = new byte[16];
|
|
dg.doFinal(md5Bytes, 0);
|
|
md5Bytes[6] &= 0x0f;
|
|
md5Bytes[6] |= 0x30;
|
|
md5Bytes[8] &= 0x3f;
|
|
md5Bytes[8] |= 0x80;
|
|
return new EaglercraftUUID(md5Bytes);
|
|
}
|
|
|
|
public static EaglercraftUUID randomUUID() {
|
|
byte[] randomBytes = new byte[16];
|
|
(new EaglercraftRandom()).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 EaglercraftUUID(randomBytes);
|
|
}
|
|
|
|
@Override
|
|
public int compareTo(EaglercraftUUID val) {
|
|
return (this.msb < val.msb ? -1
|
|
: (this.msb > val.msb ? 1 : (this.lsb < val.lsb ? -1 : (this.lsb > val.lsb ? 1 : 0))));
|
|
}
|
|
|
|
} |