Skip to content

Instantly share code, notes, and snippets.

@Szer
Last active July 6, 2021 17:02
Show Gist options
  • Save Szer/f0df1bf068aeedf8ee68ea179da8ce7f to your computer and use it in GitHub Desktop.
Save Szer/f0df1bf068aeedf8ee68ea179da8ce7f to your computer and use it in GitHub Desktop.
Parsing of UUID
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