package dev.richst.libs.richuuid; import java.io.*; import java.util.Base64; import java.util.UUID; public class RichUuid { static byte[] uuidToByteArray(UUID uuid) { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); dos.writeLong(uuid.getMostSignificantBits()); dos.writeLong(uuid.getLeastSignificantBits()); dos.write(2); dos.flush(); return bos.toByteArray(); } catch (IOException ex) { // this should never be thrown, and there is no sensible way to handle it throw new IllegalStateException( "IO exception occurred working on memory backed streams", ex); } } static UUID byteArrayToUuid(byte[] uuidBytes) { try { ByteArrayInputStream bis = new ByteArrayInputStream(uuidBytes); DataInputStream dis = new DataInputStream(bis); long msb = dis.readLong(); long lsb = dis.readLong(); return new UUID(msb, lsb); } catch (IOException ex) { // this should never be thrown, and there is no sensible way to handle it throw new IllegalStateException( "IO exception occurred working on memory backed streams", ex); } } public static String fromUUID(UUID uuid) { byte[] uuidBytes = uuidToByteArray(uuid); byte[] uuidBytesWithChecksum = new byte[18]; int checksum = 0; for (int ii = 0; ii < 16; ii++) { uuidBytesWithChecksum[ii] = uuidBytes[ii]; checksum += uuidBytes[ii] & 0xFF; } uuidBytesWithChecksum[16] = 0; uuidBytesWithChecksum[17] = (byte) (checksum % 256); return Base64.getUrlEncoder().encodeToString(uuidBytesWithChecksum); } public static String generate() { return fromUUID(UUID.randomUUID()); } private static boolean validateChecksum(byte[] uuidBytesWithChecksum) { int checksum = 0; for (int ii = 0; ii < 17; ii++) { checksum += uuidBytesWithChecksum[ii] & 0xFF; } return ((byte) checksum) == uuidBytesWithChecksum[17]; } private static void assertChecksumValid(byte[] uuidBytes) { if (!validateChecksum(uuidBytes)) { throw new InvalidRichUuidException("checksum invalid"); } } public static UUID toUUID(String richUuid) { byte[] uuidBytesWithChecksum; try { uuidBytesWithChecksum = Base64.getUrlDecoder().decode(richUuid); } catch (IllegalArgumentException ex) { throw new InvalidRichUuidException("Could not base64 decode richUuid", ex); } if (uuidBytesWithChecksum.length != 18) { throw new InvalidRichUuidException("UUID length invalid"); } assertChecksumValid(uuidBytesWithChecksum); return byteArrayToUuid(uuidBytesWithChecksum); } }