forked from benasher44/uuid
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add namespaced UUIDs v3 and v5 (benasher44#87)
- Loading branch information
1 parent
e67f02d
commit cdf8d40
Showing
13 changed files
with
20,573 additions
and
52 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package com.benasher44.uuid | ||
|
||
import kotlinx.cinterop.addressOf | ||
import kotlinx.cinterop.reinterpret | ||
import kotlinx.cinterop.usePinned | ||
import platform.CoreCrypto.CC_MD5 | ||
import platform.CoreCrypto.CC_MD5_DIGEST_LENGTH | ||
import platform.CoreCrypto.CC_SHA1 | ||
import platform.CoreCrypto.CC_SHA1_DIGEST_LENGTH | ||
|
||
/** | ||
* Constructs a "Name-Based" version 3 [UUID][Uuid]. | ||
* | ||
* Version 3 UUIDs are created by combining a name and | ||
* a namespace using the MD5 hash function. | ||
* | ||
* @param namespace for the "Name-Based" UUID | ||
* @param name withing the namespace for the "Name-Based" UUID | ||
* @return New version 3 [UUID][Uuid]. | ||
* @see <a href="https://tools.ietf.org/html/rfc4122#section-4.3">RFC 4122: Section 4.3</a> | ||
*/ | ||
@ExperimentalStdlibApi | ||
public fun uuid3Of(namespace: Uuid, name: String): Uuid = | ||
nameBasedUuidOf(namespace, name, AppleHasher(AppleHasher.Companion::md5Digest, 3)) | ||
|
||
/** | ||
* Constructs a "Name-Based" version 5 [UUID][Uuid]. | ||
* | ||
* Version 5 UUIDs are created by combining a name and | ||
* a namespace using the SHA-1 hash function. | ||
* | ||
* @param namespace for the "Name-Based" UUID | ||
* @param name withing the namespace for the "Name-Based" UUID | ||
* @return New version 5 [UUID][Uuid]. | ||
* @see <a href="https://tools.ietf.org/html/rfc4122#section-4.3">RFC 4122: Section 4.3</a> | ||
*/ | ||
@ExperimentalStdlibApi | ||
public fun uuid5Of(namespace: Uuid, name: String): Uuid = | ||
nameBasedUuidOf(namespace, name, AppleHasher(AppleHasher.Companion::sha1Digest, 5)) | ||
|
||
private class AppleHasher( | ||
private val digestFunc: (ByteArray) -> ByteArray, | ||
override val version: Int | ||
) : UuidHasher { | ||
private var data = ByteArray(0) | ||
|
||
override fun update(input: ByteArray) { | ||
val prevLength = data.size | ||
data = data.copyOf(data.size + input.size) | ||
input.copyInto(data, prevLength) | ||
} | ||
|
||
override fun digest(): ByteArray { | ||
return digestFunc(data) | ||
} | ||
|
||
companion object { | ||
fun sha1Digest(data: ByteArray): ByteArray { | ||
return ByteArray(CC_SHA1_DIGEST_LENGTH).also { bytes -> | ||
bytes.usePinned { digestPin -> | ||
data.usePinned { dataPin -> | ||
CC_SHA1(dataPin.addressOf(0), data.size.toUInt(), digestPin.addressOf(0).reinterpret()) | ||
} | ||
} | ||
} | ||
} | ||
|
||
fun md5Digest(data: ByteArray): ByteArray { | ||
return ByteArray(CC_MD5_DIGEST_LENGTH).also { bytes -> | ||
bytes.usePinned { digestPin -> | ||
data.usePinned { dataPin -> | ||
CC_MD5(dataPin.addressOf(0), data.size.toUInt(), digestPin.addressOf(0).reinterpret()) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package com.benasher44.uuid | ||
|
||
import kotlin.native.concurrent.isFrozen | ||
import kotlin.test.Test | ||
import kotlin.test.assertEquals | ||
import kotlin.test.assertTrue | ||
import kotlinx.cinterop.ByteVar | ||
import kotlinx.cinterop.addressOf | ||
import kotlinx.cinterop.memScoped | ||
import kotlinx.cinterop.readBytes | ||
import kotlinx.cinterop.reinterpret | ||
import kotlinx.cinterop.usePinned | ||
import platform.Foundation.NSData | ||
import platform.Foundation.NSUUID | ||
import platform.Foundation.dataWithContentsOfFile | ||
|
||
@ExperimentalStdlibApi | ||
class CocoaUuidTest { | ||
@Test | ||
fun `UUID.toString() matches NSUUID`() { | ||
val uuidL = uuid4() | ||
val nativeUuidString = uuidL.bytes.usePinned { | ||
NSUUID(it.addressOf(0).reinterpret()).UUIDString | ||
}.toLowerCase() | ||
assertEquals(uuidL.toString(), nativeUuidString) | ||
} | ||
|
||
@Test | ||
fun `UUID bytes match NSUUID`() { | ||
val uuidL = uuid4() | ||
val nativeUuid = NSUUID(uuidL.toString()) | ||
val nativeBytes = ByteArray(UUID_BYTES) | ||
nativeBytes.usePinned { | ||
nativeUuid.getUUIDBytes(it.addressOf(0).reinterpret()) | ||
} | ||
assertTrue(uuidL.bytes.contentEquals(nativeBytes)) | ||
} | ||
|
||
@Test | ||
fun `UUID is frozen after initialization`() { | ||
assertTrue(uuid4().isFrozen) | ||
} | ||
|
||
@Test | ||
fun `test uuid5`() { | ||
enumerateUuid5Data { namespace, name, result -> | ||
assertEquals(result, uuid5Of(namespace, name)) | ||
} | ||
} | ||
|
||
@Test | ||
fun `test uuid3`() { | ||
enumerateUuid3Data { namespace, name, result -> | ||
assertEquals(result, uuid3Of(namespace, name)) | ||
} | ||
} | ||
} | ||
|
||
private fun enumerateUuid3Data(enumerationLambda: (namespace: Uuid, name: String, result: Uuid) -> Unit) { | ||
enumerateData("src/commonTest/data/uuid3.txt", enumerationLambda) | ||
} | ||
|
||
private fun enumerateUuid5Data(enumerationLambda: (namespace: Uuid, name: String, result: Uuid) -> Unit) { | ||
enumerateData("src/commonTest/data/uuid5.txt", enumerationLambda) | ||
} | ||
|
||
private fun enumerateData(path: String, enumerationLambda: (namespace: Uuid, name: String, result: Uuid) -> Unit) { | ||
val data = NSData.dataWithContentsOfFile("$PROJECT_DIR_ROOT/$path")!! | ||
val str = memScoped { | ||
data.bytes!!.getPointer(this) | ||
.reinterpret<ByteVar>() | ||
.readBytes(data.length.toInt()) | ||
.decodeToString() | ||
} | ||
for (row in str.split("\n")) { | ||
if (row.isEmpty()) continue | ||
val (namespaceStr, name, resultStr) = row.split(",") | ||
enumerationLambda(uuidFrom(namespaceStr), name, uuidFrom(resultStr)) | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains 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
Oops, something went wrong.