veilid/veilid-flutter/lib/veilid_encoding.dart

186 lines
5.5 KiB
Dart
Raw Normal View History

2023-05-29 14:24:57 -05:00
import 'dart:convert';
2023-07-05 17:48:06 -05:00
import 'package:equatable/equatable.dart';
2023-10-14 19:18:37 -05:00
import 'package:flutter/foundation.dart';
2023-07-05 17:48:06 -05:00
import 'package:freezed_annotation/freezed_annotation.dart';
2023-10-14 19:18:37 -05:00
import 'veilid_stub.dart'
if (dart.library.io) 'veilid_ffi.dart'
if (dart.library.js) 'veilid_js.dart';
2023-05-29 14:24:57 -05:00
String base64UrlNoPadEncode(List<int> bytes) {
var x = base64Url.encode(bytes);
while (x.endsWith('=')) {
x = x.substring(0, x.length - 1);
}
return x;
}
Uint8List base64UrlNoPadDecode(String source) {
source = base64Url.normalize(source);
return base64Url.decode(source);
2023-05-29 14:24:57 -05:00
}
Uint8List base64UrlNoPadDecodeDynamic(dynamic source) =>
base64UrlNoPadDecode(source as String);
2023-05-29 14:24:57 -05:00
2023-10-14 19:18:37 -05:00
class Uint8ListJsonConverter implements JsonConverter<Uint8List, dynamic> {
const Uint8ListJsonConverter() : _jsIsArray = false;
const Uint8ListJsonConverter.jsIsArray() : _jsIsArray = true;
final bool _jsIsArray;
2023-07-05 22:53:08 -05:00
@override
2023-10-14 19:18:37 -05:00
Uint8List fromJson(dynamic json) => kIsWeb && _jsIsArray
? convertUint8ListFromJson(json)
: base64UrlNoPadDecode(json as String);
2023-07-05 22:53:08 -05:00
@override
2023-10-14 19:18:37 -05:00
dynamic toJson(Uint8List data) => kIsWeb && _jsIsArray
? convertUint8ListToJson(data)
: base64UrlNoPadEncode(data);
2023-07-05 22:53:08 -05:00
}
2023-07-05 17:48:06 -05:00
@immutable
abstract class EncodedString extends Equatable {
2023-07-26 13:20:17 -05:00
const EncodedString(String s) : contents = s;
2023-07-05 17:48:06 -05:00
final String contents;
@override
List<Object> get props => [contents];
2023-05-29 14:24:57 -05:00
2023-07-26 13:20:17 -05:00
Uint8List decode() => base64UrlNoPadDecode(contents);
2023-05-29 14:24:57 -05:00
@override
2023-07-05 17:48:06 -05:00
String toString() => contents;
2023-05-29 14:24:57 -05:00
2024-05-15 20:20:39 -05:00
static int encodedLength<T extends EncodedString>() {
switch (T) {
case FixedEncodedString32:
return FixedEncodedString32.encodedLength();
case FixedEncodedString43:
return FixedEncodedString43.encodedLength();
case FixedEncodedString86:
return FixedEncodedString86.encodedLength();
default:
throw UnimplementedError();
}
}
static int decodedLength<T extends EncodedString>() {
switch (T) {
case FixedEncodedString32:
return FixedEncodedString32.decodedLength();
case FixedEncodedString43:
return FixedEncodedString43.decodedLength();
case FixedEncodedString86:
return FixedEncodedString86.decodedLength();
default:
throw UnimplementedError();
}
}
2023-07-12 20:28:00 -05:00
static T fromBytes<T extends EncodedString>(Uint8List bytes) {
switch (T) {
case FixedEncodedString32:
return FixedEncodedString32.fromBytes(bytes) as T;
case FixedEncodedString43:
return FixedEncodedString43.fromBytes(bytes) as T;
case FixedEncodedString86:
return FixedEncodedString86.fromBytes(bytes) as T;
default:
throw UnimplementedError();
}
}
2023-05-29 14:24:57 -05:00
static T fromString<T extends EncodedString>(String s) {
switch (T) {
case FixedEncodedString32:
2023-07-05 17:48:06 -05:00
return FixedEncodedString32.fromString(s) as T;
2023-05-29 14:24:57 -05:00
case FixedEncodedString43:
2023-07-05 17:48:06 -05:00
return FixedEncodedString43.fromString(s) as T;
2023-05-29 14:24:57 -05:00
case FixedEncodedString86:
2023-07-05 17:48:06 -05:00
return FixedEncodedString86.fromString(s) as T;
2023-05-29 14:24:57 -05:00
default:
throw UnimplementedError();
}
}
}
2023-07-05 17:48:06 -05:00
@immutable
2023-05-29 14:24:57 -05:00
class FixedEncodedString32 extends EncodedString {
2023-07-12 20:28:00 -05:00
factory FixedEncodedString32.fromBytes(Uint8List bytes) {
if (bytes.length != decodedLength()) {
2023-07-26 13:20:17 -05:00
throw Exception('length ${bytes.length} should be ${decodedLength()}');
2023-07-12 20:28:00 -05:00
}
return FixedEncodedString32._(base64UrlNoPadEncode(bytes));
}
2023-07-05 17:48:06 -05:00
factory FixedEncodedString32.fromString(String s) {
2023-07-26 13:20:17 -05:00
final d = base64UrlNoPadDecode(s);
2023-07-05 17:48:06 -05:00
if (d.length != decodedLength()) {
2023-07-26 13:20:17 -05:00
throw Exception('length ${s.length} should be ${encodedLength()}');
2023-07-05 17:48:06 -05:00
}
return FixedEncodedString32._(s);
2023-05-29 14:24:57 -05:00
}
2023-07-05 17:48:06 -05:00
factory FixedEncodedString32.fromJson(dynamic json) =>
FixedEncodedString32.fromString(json as String);
2023-07-26 13:20:17 -05:00
const FixedEncodedString32._(super.s);
static int encodedLength() => 32;
static int decodedLength() => 24;
String toJson() => toString();
2023-05-29 14:24:57 -05:00
}
2023-07-05 17:48:06 -05:00
@immutable
2023-05-29 14:24:57 -05:00
class FixedEncodedString43 extends EncodedString {
2023-07-12 20:28:00 -05:00
factory FixedEncodedString43.fromBytes(Uint8List bytes) {
if (bytes.length != decodedLength()) {
2023-07-26 13:20:17 -05:00
throw Exception('length ${bytes.length} should be ${decodedLength()}');
2023-07-12 20:28:00 -05:00
}
return FixedEncodedString43._(base64UrlNoPadEncode(bytes));
}
2023-07-05 17:48:06 -05:00
factory FixedEncodedString43.fromString(String s) {
2023-07-26 13:20:17 -05:00
final d = base64UrlNoPadDecode(s);
2023-07-05 17:48:06 -05:00
if (d.length != decodedLength()) {
2023-07-26 13:20:17 -05:00
throw Exception('length ${s.length} should be ${encodedLength()}');
2023-07-05 17:48:06 -05:00
}
return FixedEncodedString43._(s);
2023-05-29 14:24:57 -05:00
}
2023-07-05 17:48:06 -05:00
factory FixedEncodedString43.fromJson(dynamic json) =>
FixedEncodedString43.fromString(json as String);
2023-07-26 13:20:17 -05:00
const FixedEncodedString43._(super.s);
static int encodedLength() => 43;
static int decodedLength() => 32;
String toJson() => toString();
2023-05-29 14:24:57 -05:00
}
2023-07-05 17:48:06 -05:00
@immutable
2023-05-29 14:24:57 -05:00
class FixedEncodedString86 extends EncodedString {
2023-07-12 20:28:00 -05:00
factory FixedEncodedString86.fromBytes(Uint8List bytes) {
if (bytes.length != decodedLength()) {
2023-07-26 13:20:17 -05:00
throw Exception('length ${bytes.length} should be ${decodedLength()}');
2023-07-12 20:28:00 -05:00
}
return FixedEncodedString86._(base64UrlNoPadEncode(bytes));
}
2023-07-05 17:48:06 -05:00
factory FixedEncodedString86.fromString(String s) {
2023-07-26 13:20:17 -05:00
final d = base64UrlNoPadDecode(s);
2023-07-05 17:48:06 -05:00
if (d.length != decodedLength()) {
2023-07-26 13:20:17 -05:00
throw Exception('length ${s.length} should be ${encodedLength()}');
2023-07-05 17:48:06 -05:00
}
return FixedEncodedString86._(s);
}
factory FixedEncodedString86.fromJson(dynamic json) =>
FixedEncodedString86.fromString(json as String);
2023-07-26 13:20:17 -05:00
const FixedEncodedString86._(super.s);
static int encodedLength() => 86;
static int decodedLength() => 64;
String toJson() => toString();
2023-05-29 14:24:57 -05:00
}