LibAC-dart/lib/utils/uuid/UUID.dart

163 lines
4.7 KiB
Dart

import 'dart:convert';
import 'dart:math';
import 'package:crypto/crypto.dart';
import 'package:libac_flutter/nbt/Stream.dart';
class UUID {
late final int LSB;
late final int MSB;
UUID(int msb, int lsb) {
MSB = msb.abs();
LSB = lsb.abs();
}
static final UUID ZERO = UUID.generate(0);
/// Validates whether the given [uuid] is a valid UUID.
static bool validate(String uuid) {
try {
parse(uuid);
return true;
} catch (e) {
return false;
}
}
/// Parses the given [uuid] string and returns a UUID object.
static UUID parse(String uuid) {
if (validate(uuid)) {
final segments = uuid.split('-');
if (segments.length != 5) {
throw const FormatException('Invalid UUID format');
}
final msbString = segments.sublist(0, 3).join('');
final lsbString = segments.sublist(3, 5).join('');
final msb = int.parse(msbString, radix: 16);
final lsb = int.parse(lsbString, radix: 16);
return UUID(msb, lsb);
} else
return UUID.ZERO;
}
@override
String toString() {
final msbHex = MSB.toRadixString(16).padLeft(16, '0');
final lsbHex = LSB.toRadixString(16).padLeft(16, '0');
return '${msbHex.substring(0, 8)}-${msbHex.substring(8, 12)}-${msbHex.substring(12, 16)}-${lsbHex.substring(0, 4)}-${lsbHex.substring(4, 16)}';
}
/// Returns the Most Significant Bits (MSB) long value of the UUID.
int getMostSignificantBits() => MSB;
/// Returns the Least Significant Bits (LSB) long value of the UUID.
int getLeastSignificantBits() => LSB;
/// Factory method to generate UUID of the specific version.
factory UUID.generate(int version, {List<Object>? parameters}) {
List<Object> params = [];
if (parameters == null) {
if (version != 4) {
return UUID.generate(4);
}
} else
params = parameters!;
switch (version) {
case 0:
return UUID(0, 0);
case 3:
{
if (params.length != 2)
throw Exception(
"UUID v3 requires two parameters, [namespace,name]");
String namespace = params[0] as String;
String name = params[1] as String;
ByteLayer layer = ByteLayer();
if (!namespace.isEmpty) {
final namespaceBytes = utf8.encode(namespace);
layer.writeBytes(namespaceBytes);
}
if (!name.isEmpty) {
final nameBytes = utf8.encode(name);
layer.writeBytes(nameBytes);
}
var bytes = md5.convert(List.from(layer.bytes)).bytes;
layer.clear();
layer.writeBytes(bytes);
layer.unsetSetBit(6, 0x0F, 0x30);
print(
"Existing bit at position 8: ${layer.getBit(8).toRadixString(2)}:${layer.getBit(8)}");
layer.unsetSetBit(8, 0x3F, 0x80);
print(
"New bit at position 8: ${layer.getBit(8).toRadixString(2)}:${layer.getBit(8)}");
layer.resetPosition();
var msb = layer.readUnsignedLong();
var lsb = layer.readUnsignedLong();
if (msb < 0) print("Most significant bit is negative!");
if (lsb < 0) print("Least significant bit is negative!");
return UUID(msb, lsb);
}
case 4:
{
ByteLayer layer = ByteLayer();
final random = Random.secure();
layer.writeLong(
(random.nextInt(0xFFFFFFFF) << 32) | random.nextInt(0xFFFFFFFF));
layer.writeLong(
(random.nextInt(0xFFFFFFFF) << 32) | random.nextInt(0xFFFFFFFF));
layer.unsetSetBit(6, 0x0F, 0x40);
layer.unsetSetBit(8, 0x3F, 0x80);
layer.resetPosition();
return UUID(layer.readUnsignedLong(), layer.readUnsignedLong());
}
case 5:
{
ByteLayer layer = ByteLayer();
if (params.length != 2)
throw Exception(
"UUID v5 requires two parameters, [namespace,name]");
String namespace = params[0] as String;
String name = params[1] as String;
if (!namespace.isEmpty) {
final namespaceBytes = utf8.encode(namespace);
layer.writeBytes(namespaceBytes);
}
if (!name.isEmpty) {
final nameBytes = utf8.encode(name);
layer.writeBytes(nameBytes);
}
final hashBytes = sha1.convert(List.from(layer.bytes)).bytes;
layer.clear();
layer.writeBytes(hashBytes);
layer.unsetSetBit(6, 0x0F, 0x50);
layer.unsetSetBit(8, 0x3F, 0x80);
layer.resetPosition();
return UUID(layer.readUnsignedLong(), layer.readUnsignedLong());
}
default:
throw ArgumentError('Unsupported UUID version: $version');
}
}
}