Last active
July 6, 2021 17:02
-
-
Save Szer/f0df1bf068aeedf8ee68ea179da8ce7f to your computer and use it in GitHub Desktop.
Parsing of UUID
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.* | |
import java.util.UUID | |
// java.util.UUID.fromString doesn't enforce string representation of UUID https://www.ietf.org/rfc/rfc4122.txt | |
// It requires 4 '-' to present with any hex numbers in between. So it treats 1-1-1-1-1 as a valid UUID | |
// I don't think it's valid string representation of UUID. RFC4122 also doesn't think so | |
// Open JDK bug: https://bugs.openjdk.java.net/browse/JDK-8216407 | |
// That's why we have our own UUID parser here | |
// Taken from here https://github.com/openjdk/jdk/blob/f485171ce8c7e9c9d7d2c24e1807efaa6ff137e8/src/java.base/share/classes/java/util/UUID.java#L212-L259 | |
// But without "wrong" part | |
object UUIDFixed { | |
private val NIBBLES by lazy { | |
val ns = ByteArray(256) | |
Arrays.fill(ns, (-1).toByte()) | |
ns['0'.code] = 0 | |
ns['1'.code] = 1 | |
ns['2'.code] = 2 | |
ns['3'.code] = 3 | |
ns['4'.code] = 4 | |
ns['5'.code] = 5 | |
ns['6'.code] = 6 | |
ns['7'.code] = 7 | |
ns['8'.code] = 8 | |
ns['9'.code] = 9 | |
ns['A'.code] = 10 | |
ns['B'.code] = 11 | |
ns['C'.code] = 12 | |
ns['D'.code] = 13 | |
ns['E'.code] = 14 | |
ns['F'.code] = 15 | |
ns['a'.code] = 10 | |
ns['b'.code] = 11 | |
ns['c'.code] = 12 | |
ns['d'.code] = 13 | |
ns['e'.code] = 14 | |
ns['f'.code] = 15 | |
ns | |
} | |
private fun parse4Nibbles(name: String, pos: Int): Long { | |
val ns = NIBBLES | |
val ch1 = name[pos] | |
val ch2 = name[pos + 1] | |
val ch3 = name[pos + 2] | |
val ch4 = name[pos + 3] | |
return if (ch1.code or ch2.code or ch3.code or ch4.code > 0xff) | |
-1 | |
else | |
(ns[ch1.code].toInt() shl 12 or (ns[ch2.code].toInt() shl 8) or (ns[ch3.code].toInt() shl 4) or ns[ch4.code].toInt()).toLong() | |
} | |
fun String.toUUID(): UUID { | |
if (this.length == 36) { | |
val ch1 = this[8] | |
val ch2 = this[13] | |
val ch3 = this[18] | |
val ch4 = this[23] | |
if (ch1 == '-' && ch2 == '-' && ch3 == '-' && ch4 == '-') { | |
val msb1 = parse4Nibbles(this, 0) | |
val msb2 = parse4Nibbles(this, 4) | |
val msb3 = parse4Nibbles(this, 9) | |
val msb4 = parse4Nibbles(this, 14) | |
val lsb1 = parse4Nibbles(this, 19) | |
val lsb2 = parse4Nibbles(this, 24) | |
val lsb3 = parse4Nibbles(this, 28) | |
val lsb4 = parse4Nibbles(this, 32) | |
if (msb1 or msb2 or msb3 or msb4 or lsb1 or lsb2 or lsb3 or lsb4 >= 0) { | |
return UUID( | |
msb1 shl 48 or (msb2 shl 32) or (msb3 shl 16) or msb4, | |
lsb1 shl 48 or (lsb2 shl 32) or (lsb3 shl 16) or lsb4 | |
) | |
} | |
} | |
} | |
throw IllegalArgumentException("UUID should contain 32 digits with 4 dashes. Expected: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Actual: $this") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment