Push more utilities and UUID stuff
This commit is contained in:
parent
dd6ee1bf60
commit
9b7b84153f
7 changed files with 325 additions and 0 deletions
|
@ -1,11 +1,13 @@
|
|||
import 'package:libac_flutter/nbt/impl/ByteTag.dart';
|
||||
import 'package:libac_flutter/nbt/impl/CompoundTag.dart';
|
||||
import 'package:libac_flutter/nbt/impl/DoubleTag.dart';
|
||||
import 'package:libac_flutter/nbt/impl/IntArrayTag.dart';
|
||||
import 'package:libac_flutter/nbt/impl/IntTag.dart';
|
||||
import 'package:libac_flutter/nbt/impl/ListTag.dart';
|
||||
import 'package:libac_flutter/utils/Vector3.dart';
|
||||
|
||||
import '../utils/Vector2.dart';
|
||||
import '../utils/uuid/UUID.dart';
|
||||
|
||||
class NbtUtils {
|
||||
static void writeBoolean(CompoundTag tag, String name, bool b) {
|
||||
|
@ -89,4 +91,29 @@ class NbtUtils {
|
|||
return Vector3i.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
static List<int> _msbLsbToIntArray(int msb, int lsb) {
|
||||
return [msb >> 32, msb, lsb >> 32, lsb];
|
||||
}
|
||||
|
||||
static List<int> _uuidToIntArray(UUID ID) {
|
||||
return _msbLsbToIntArray(
|
||||
ID.getMostSignificantBits(), ID.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
static UUID _uuidFromIntArray(List<int> values) {
|
||||
return UUID((values[0] << 32 | values[1] & 4294967295),
|
||||
(values[2] << 32 | values[3] & 4294967295));
|
||||
}
|
||||
|
||||
static void writeUUID(CompoundTag tag, String name, UUID ID) {
|
||||
tag.put(name, IntArrayTag.valueOf(_uuidToIntArray(ID)));
|
||||
}
|
||||
|
||||
static UUID readUUID(CompoundTag tag, String name) {
|
||||
if (!tag.contains(name))
|
||||
return UUID.ZERO;
|
||||
else
|
||||
return _uuidFromIntArray(tag.get(name)!.asIntArray());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -283,4 +283,74 @@ class ByteLayer {
|
|||
int value = readLong();
|
||||
return (value >> 1) ^ (-(value & 1));
|
||||
}
|
||||
|
||||
void writeBytes(Iterable<int> bytes) {
|
||||
for (int byte in bytes) {
|
||||
writeByte(byte);
|
||||
}
|
||||
}
|
||||
|
||||
List<int> readBytes(int num) {
|
||||
List<int> lst = [];
|
||||
for (int i = 0; i < num; i++) {
|
||||
lst.add(readByte());
|
||||
}
|
||||
|
||||
return lst;
|
||||
}
|
||||
|
||||
void setBit(int position, int maskToSet) {
|
||||
if (position < _byteBuffer.length) {
|
||||
// Set the value now
|
||||
seek(position);
|
||||
int current = readByte();
|
||||
seek(position);
|
||||
current |= maskToSet;
|
||||
writeByte(current);
|
||||
}
|
||||
}
|
||||
|
||||
void clearBit(int position, int maskToClear) {
|
||||
if (position < _byteBuffer.length) {
|
||||
// Lets clear the bit
|
||||
seek(position);
|
||||
int current = readByte();
|
||||
current &= maskToClear;
|
||||
seek(position);
|
||||
writeByte(current);
|
||||
}
|
||||
}
|
||||
|
||||
bool checkBit(int position, int mask) {
|
||||
if (position < _byteBuffer.length) {
|
||||
seek(position);
|
||||
int current = readByte();
|
||||
return (current & mask) == mask;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
int getBit(int position) {
|
||||
if (position < _byteBuffer.length) {
|
||||
seek(position);
|
||||
return readByte();
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void seek(int position) {
|
||||
_position = 0;
|
||||
_ensureCapacity(position);
|
||||
_position = position;
|
||||
}
|
||||
|
||||
void waitSetBit(int position, int maskToClear, int maskToSet) {
|
||||
clearBit(position, maskToClear);
|
||||
setBit(position, maskToSet);
|
||||
|
||||
while (!checkBit(position, maskToSet)) {
|
||||
clearBit(position, maskToClear);
|
||||
setBit(position, maskToSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,10 @@ class IntArrayTag extends Tag {
|
|||
this.value.addAll(value);
|
||||
}
|
||||
|
||||
static IntArrayTag valueOf(List<int> value) {
|
||||
return IntArrayTag._(value);
|
||||
}
|
||||
|
||||
@override
|
||||
void readValue(ByteLayer data) {
|
||||
int count = data.readInt();
|
||||
|
|
161
lib/utils/uuid/UUID.dart
Normal file
161
lib/utils/uuid/UUID.dart
Normal file
|
@ -0,0 +1,161 @@
|
|||
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) {
|
||||
if (msb < 0)
|
||||
MSB = -msb;
|
||||
else
|
||||
MSB = msb;
|
||||
|
||||
if (lsb < 0)
|
||||
LSB = -lsb;
|
||||
else
|
||||
LSB = lsb;
|
||||
}
|
||||
|
||||
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.waitSetBit(6, 0x0F, 0x30);
|
||||
layer.waitSetBit(8, 0x3F, 0x80);
|
||||
|
||||
layer.resetPosition();
|
||||
|
||||
return UUID(layer.readLong(), layer.readLong());
|
||||
}
|
||||
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.waitSetBit(6, 0x0F, 0x40);
|
||||
layer.waitSetBit(8, 0x3F, 0x80);
|
||||
|
||||
layer.resetPosition();
|
||||
|
||||
return UUID(layer.readLong(), layer.readLong());
|
||||
}
|
||||
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.waitSetBit(6, 0x0F, 0x50);
|
||||
layer.waitSetBit(8, 0x3F, 0x80);
|
||||
|
||||
layer.resetPosition();
|
||||
|
||||
return UUID(layer.readLong(), layer.readLong());
|
||||
}
|
||||
default:
|
||||
throw ArgumentError('Unsupported UUID version: $version');
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue